Java 的内存区域:
堆:对象(成员变量)
栈:局部变量(形参)
方法区:类的所有信息
内存溢出:
剩余内存不足以分配给请求的资源:OutOfMemoryError
内存泄漏: 分配出去的内存回收不回来
GC:是一个守护(后台)线程 System.gc() finalize():任何一个对象所属的类中都有这个方法,作用:GC回收对象前,做最后的资源释放
public class Student {
private int id;
public Student() {
super();
// TODO Auto-generated constructor stub
}
public Student(int id) {
super();
this.id = id;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@Override
public String toString() {
return "Student [id=" + id + "]";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + id;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Student other = (Student) obj;
if (id != other.id)
return false;
return true;
}
@Override
protected void finalize() throws Throwable {
System.out.println("最后的资源释放");
}
}
public class FinalizeDemo {
public static void main(String[] args) {
//创建一个Student对象
Student student = new Student(1);
//一系列对此对象的引用操作
//对象使用结束
student = null;
//让GC尽快回收此垃圾
System.gc();
}
}
案例:
public class Demo01 {
public static void main(String[] args) {
int i = 3;
String str = "gbk";
char[] chs = {'a','b','c'};
Demo01 demo01 = new Demo01();
demo01.change(i, chs);
//System.out.println(str); //gbk
System.out.println(i) //3
System.out.println(chs); //k b c
}
public void change(int i,char[] chs){
//str1 = "abk";
i = 12;
chs[0] = 'k';
}
}
问题:Java中参数的传递是值传递还是引用传递
Java中的参数传递只有值传递
特点:封装,继承,多态
各自特点注意点:
1.封装中的成员变量的数据类型一定是引用类型
2.继承注意点:
子类继承父类,不继承的成员有哪些?
私有的,构造方法,static成员
注意点:对象的初始化顺序
案例:
public class Super {
int a = 6;
public Super(){
test();
}
public void test(){
System.out.println(a);
}
}
public class Sub extends Super {
int a = 8;
public Sub(){
test();
}
public void test(){
System.out.println(a);
}
}
public static void main(String[] args) {
new Sub();
}
打印结果: 0 8
重写:不论是通过父类的引用还是子类的引用指向子类对象,调用到的都是重写后的方法
Super su = new Sub();
Sub sub = new Sub();
su.test()
sub.test()
重写遵循运行期绑定原则
案例2:
public class ExtendsConstrutorsDemo02 {
public static void main(String[] args) {
new B();
}
}
class A{
A(){
System.out.println("A构造方法");
}
}
class C{
C(){
System.out.println("C构造方法");
}
}
class B extends A{
private C c = new C();
B(){
System.out.println("B构造方法");
}
}
打印结果: A C B
考点:构造方法中的执行顺序:super()->初始化成员变量->执行其余代码
父类 引用 = new 子类对象
1.向下造型:
如何正确的向下造型
造型成的类型必须和运行期对象的类型是一致的。
前提:
class Teacher extends Person
class Student extends Person
正确的向下造型:
Person per = new Student();
Student stu = (Student)per;
不正确的向下造型
情况1:
Person per = new Student();
Teacher te = (Teacher)per;
情况2:
Person per = new Person();
Student stu = (Student)per;
2.强制造型2:
public class ClassCastDemo02 {
public static void main(String[] args) {
//向上造型
SuperCls cls = new SubCls();
//想访问到子类中的test方法
//方式一:向下造型
// SubCls cls2 = (SubCls)cls;
// cls2.test();
//方式二:强制造型成接口类型
// T1 t = (T1)cls;
// t.test();
//错误的强制造型
SuperCls cls2 = new SubCls1();
T1 t = (T1)cls2;
}
}
interface T1{
void test();
}
class SuperCls{
public void demo(){}
}
class SubCls1 extends SuperCls{
@Override
public void demo() {
}
}
class SubCls extends SuperCls implements T1{
@Override
public void test() {}
@Override
public void demo() {}
public void myMethod(){}
}
可以通过强制造型,将super引用转型成T1类型
Super-->T1
T1 t = (T1)super;
t.test()
造型成的类型必须和运行期的对象类型有关系。
用法:引用 instanceof 数据类型 - boolean
toString() 类型@散列码值(十六进制)
hashCode() int(十进制)
equals():用于比较两个对象是否相等,作用等同于==,通常建议重写,使其更具有实际意义,JAVAAPI中的很多类都重写了此方法
自动装箱,自动拆箱
1.String类对象一旦创建,值不可以改变
2.String本质是字符数组 : toCharArray():char[]
3.String对象的创建:2种方法
方式一:new String(String str) :保存与堆中
方式二:"" :保存在常量池
常见面试题:
1.String str = new String("abc")问:创建了几个String对象: 2个
2.String s1 = "a",s2 = "b",s3 = "ab",s4 = "a"+"b", s5 = s1+s2;
问题:s3==s4 true s3==s5 false
StringBuilder:用于字符串操作
原理:底层是动态数组,可以实现在同一个对象基础上进行字符串的修改拼接操作
拼接,修改,删除
构造方法:new StringBuilder(String str)
注意点: String的拼接可以使用 String+String,会产生新的String对象,这种方式的拼接底层其实采用的就是StringBuilder
String s1 = "a",s2 = "b"
String s3 = s1+s2; //新创建String对象
其底层实现是:
StringBuilder builder = new StringBuilder(s1);
builder.append(s2);
String s3 = builder.toString();
StringBuffer
和StrinbBuilderAPI是一样的。区别在于StringBuilder是非线程安全的,效率更高,StringBuffer是线程安全的,效率稍低
1.Date:
Date date = new Date();
getTime():long
setTime(long)
2.SimpleDateFormat
//用户输入的字符串的日期表示 2018-04-26
//要求java程序将此日期用户程序中使用 String->Date
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
//String -->Date
Date date = sdf.parse(str)
Calendar:抽象类
对象的创建:2种方法
1.创建其子类对象
2.调用其static方法getInstance():Calendar-常用的
用于获取或设置日历的字段值
1.get系列方法: get(int Field):int 用于获取指定日历的日历字段值 Field:YEAR MONTH DATE DAYOFWEEK
getTime():Date
getTimeInMills():long
2.set系列
set(int Field,int value)
setTime(Date)
3.add(int field,int amount)
正则表达式:
字符集
单个字符表示的字符集
[abc] [a-zA-Z0-9]
预定义字符:
. 任意字符
\d 所有数字
\w [a-zA-Z0-9_]
\s 所有的空白字符 \r \n \t
\D 非数字
\W 与\w相反
\S 非空白字符
使用预定义字符集需要转义 \
数量词字符:
? 0/1
+ >=1
* 任意次
{m} 前一个字符正好匹配m次
{m,} 前一个字符匹配>=m次
{m,n} 前一个字符匹配m<=x<=n
分组():将多个部分看成一个整体,通常是和|配合使用的
案例:匹配用户输入的手机号 +86|0086 手机号
边界匹配:^开始 $结尾
在Java中写正则表达式可以省略边界匹配符,前提:调用matches方法。原因:matches方法自带边界匹配功能。
String类中的正则API:
matches(String regex):boolean
split(String regex):String[]
repalceAll(String regex,String replacement)
案例:用户输入字符串的日期格式 : yyyy-MM-dd,要求用户输入的日期必须符合现实,月份1-12,日期取决于月份 -- 分组
思路:
大月:135781012 - 31
小月:46911 - 30
二月:2 - 28
String regex = "[1-9]\\d{3}-(
((0[13578]|1[02])-(0[1-9]|[12][0-9]|3[01]))
|((0[469]|11)-(0[1-9]|[12][0-9]|30))
|(02-(0[1-9]|1[0-9]|2[0-8])))"
规律:()通常都是和|配合使用的,|的外面都会有()
Collection:接口
方法
List子接口:可重复集
特点:线性表 ,有索引操作的
1.方法
2.List和Array的转换
List集合可以转换成Array
toArray():Object[]
toArray(T[] a):T[]:常用的
Array转换成List
String[] ary = {...}
ary -- >List
Arrays.asList():List<String>
Arrays.asList(T...a):List<T>
T...a:可变参数
可变参数:
1.可变参数的实质:可变数组
2.可变参数的访问和数组的访问是一致的。
3.注意点: 1.可变参数如果出现在参数列表,那么一定是位于参数列表的最后 2.一个方法的参数列表最多只能有一个可变参数 3.如果参数是可变参数,可以传递一个数组过去
3.List集合中的排序
Collections.sort(List)
注意点:使用此种方式对集合排序有前提:List集合中的元素所属的类实现了Comparable接口,重写compareTo方法:用于定义比较规则
如果List集合中的元素所属的类没有实现Comparable接口,此时用Collections.sort(List)会编译报错
如果List集合汇总的元素所属的类已经实现了其排序规则,而现在要求对List集合排序,规则不是其元素已经定义的规则,该如何实现?
内比较器:Comparable
外比较器:Comparator
案例:List集合保存User对象,User类中已经定义好排序规则按照id排序,现要求对list集合中的元素排序,按照年龄升序排序
public class User implements Comparable<User>{
private Integer userId;
private String userName;
private Integer age;
public User() {
super();
// TODO Auto-generated constructor stub
}
public User(Integer userId, String userName, Integer age) {
super();
this.userId = userId;
this.userName = userName;
this.age = age;
}
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "User [userId=" + userId + ", userName=" + userName + ", age=" + age + "]";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((userId == null) ? 0 : userId.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
User other = (User) obj;
if (userId == null) {
if (other.userId != null)
return false;
} else if (!userId.equals(other.userId))
return false;
return true;
}
@Override
public int compareTo(User o) {
return this.userId-o.getUserId();
}
}
public class SortListDemo {
public static void main(String[] args) {
/*
* 有一个集合保存了n个user对象,现要求对此
* 集合中的所有user进行排序,排序规则:根据id升序排列
*/
User user = new User(23, "a", 23);
User user1 = new User(1, "a", 25);
User user2 = new User(33, "a", 13);
User user3 = new User(5, "a", 22);
List<User> list = new ArrayList<>();
list.add(user);
list.add(user1);
list.add(user2);
list.add(user3);
for (User user4 : list) {
System.out.println(user4);
}
/*
* 要求根据学生的年龄排序
*/
Collections.sort(list, new ByAge());
for (User user4 : list) {
System.out.println(user4);
}
}
}
class ByAge implements Comparator<User>{
@Override
public int compare(User o1, User o2) {
return o1.getAge()-o2.getAge();
}
}
Set集合:不可重复集
实现类:HashSet TreeSet:实现了排序的set集合
Map集合:
用于保存K-V对数据 K值是唯一的,V值可重复
map集合的遍历:
keySet():Set
entrySet():Set
Entry:getKey() getValue()
实现类:HashMap TreeMap
面试题:分数排序 3GB的数据存放的是1000000个学生的分数.排序取出前100名
public class Student implements Comparable<Student> {
private Integer id;
private String name;
private Integer score;
public Student() {
super();
// TODO Auto-generated constructor stub
}
public Student(Integer id, String name, Integer score) {
super();
this.id = id;
this.name = name;
this.score = score;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getScore() {
return score;
}
public void setScore(Integer score) {
this.score = score;
}
@Override
public String toString() {
return "Student [id=" + id + ", name=" + name + ", score=" + score + "]";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Student other = (Student) obj;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
return true;
}
@Override
public int compareTo(Student o) {
return this.id-o.getId();
}
}
public class SortStudent {
public static void main(String[] args) {
//创建1000000个学生并存入set集合
Set<Student> set = new TreeSet<>(new ByScore());
for(int i=0;i<1000000;i++){
Student student = new Student(i, "学生"+i, (int)(Math.random()*60000));
set.add(student);
if(set.size()>100){
Iterator<Student> it = set.iterator();
it.next();
it.remove();
}
}
for (Student student : set) {
System.out.println(student);
}
}
}
class ByScore implements Comparator<Student>{
@Override
public int compare(Student o1, Student o2) {
return o1.getScore()-o2.getScore();
}
}
构造方法: new RandomAccessFile(File/String,String mode)
mode:r rw
特点:是基于指针操作的文件操作类,此类的对象可以实现对文件数据的读和写操作
方法:
读数据,写数据方法和IO流中字节流的读写方式一样的。
seek(long pos)
getFilePointer():long
IO流:代码自己下去看笔记
线程的生命状态:5种 新建状态(NEW) 就绪状态(Runnable) 运行状态(Running) 阻塞状态(Blocked) 死亡状态(Dead)
线程的创建:2种方式
方式一:extends Thread
方式二:implements Runnable
两种方式的区别: 继承Thread方式实现了线程和任务的不可分离 实现Runnalbe接口方式实现了线程和任务的分离、
线程的启动:调用Thread类中的start()启动线程
多线程并发访问:
可能出现的问题:多线程并发安全问题,可能出现被污染的数据
如何解决:同步,异步
多线程并发是异步的
解决多线程并发安全问题:线程同步
方式:Synchronized
用法:可以用于修饰方法,修饰代码块
同步的机制:锁机制
修饰方法给调用此同步方法的对象加锁
修饰代码块可以给任意对象加锁,经常用的this
注意点:不能实现同步的情景:
情景一: class T{ public synchronized void test(){} public void demo(){} }
class Test{
main:
Thread threadA = new Thread(){
run:
T t = new T();
t.test();
};
Thread threadB = new Thread(){
run:
T t = new T();
t.test();
}
threadA.start();
threadB.start();
}
情景二: class T{ public synchronized void test(){} public void demo(){} }
class Test{
main:
T t = new T();
Thread threadA = new Thread(){
run:
t.test();
};
Thread threadB = new Thread(){
run:
t.demo();
}
threadA.start();
threadB.start();
}
同步的互斥性 class T{ public synchronized void test(){} public synchronized void demo(){} }
class Test{
main:
T t = new T();
Thread threadA = new Thread(){
run:
t.test();
};
Thread threadB = new Thread(){
run:
t.demo();
}
threadA.start();
threadB.start();
}
线程池:
创建
Executors.creatFixedThreadPool(int nThread):ExecutorService
将任务提交给线程池:
execute(Runnable)
线程池的关闭:
shutDown():将已经接受到的任务全都执行完,不接受新任务,任务执行完关闭线程池
shutDownNow():List
作用:试图终止正在执行的任务,不执行等待的任务, 并将已经接受但没执行的任务返回给list集合
TCP通信
多线程和Tcp做聊天室项目
解析:DOM4J SAX
A.10
B.7
C.13
D.14
for (int n = 2; n <= 1000; n++) {
空白处
if (s == n) {
System.out.println(n);
}
}
下列选项中,空白处可以填入的代码是:(AC)。 A.int s = 0, n1 = n; while (n1 > 0) { int t = n1 % 10; s += t * t * t; n1 /= 10; }
B.int s = 0, n1 = n; while (n1 > 0) { int t = n1 / 10; s+= t * t * t; n1 %= 10; }
C.int s = 0; for(int n1 = n; n1>0; n1 /= 10) { int t = n1%10; s += t * t * t; }
D.int s = 0; for(int n1 = n; n1>0; n1 %= 10) { int t = n1 / 10; s += t * t * t; }
int x=6, y=10, k=5;
switch( x % y )
{
case 0: k=x*y;
case 6: k=x/y;
case 12: k=x-y;
default: k=x*y-x;
}
A.60
B.5
C.0
D.54
class Test{
public static void main(String[] args){
doSomething(1);
doSomething(1,2);
}
//insert code here
}
在程序中插入下列哪一行代码可以编译通过: BD A static void doSomething(int[] args){}
B static void doSomething(int... args){}
C static coid doSomething(int...args,int x){}
D static void doSomething(int x,int...args){}
public class A {
private int counter = 0;
public static int getInstanceCount() {
return counter;
}
public A() {
counter++;
}
public static void main(String[] args) {
A a1 = new A();
A a2 = new A();
A a3 = new A();
System.out.println(A.getInstanceCount());
}
}
A.该类编译失败
B.输出:1
C.输出:3
D.输出:0
class Base {
int i = 99;
public void amethod() {
System.out.println("Base.amethod()");
}
Base() {
amethod();
}
}
public class RType extends Base {
int i = -1;
public static void main(String argv[]){
Base b = new RType();
System.out.print(b.i+"\t");
b.amethod();
RType r = (RType)b;
System.out.print(r.i+"\t");
}
public void amethod(){
System.out.print("RType.amethod()"+"\t");
}
}
A RType.amethod -1 RType.amethod -1
B RType.amethod 99 RType.amethod -1
C 99 RType.amethod 99
D 编译时错误(Compile time error)
class Base {
Base() { System.out.print("Base"); }
}
public class Alpha extends Base {
public static void main( String[] args ) {
new Alpha();
new Base();
}
}
A.Base
B.BaseBase
C.程序编译失败.
D.程序运行但没有任何输出
public class CountSubString {
public static void main(String[] args) {
String str = "fdasafdasfdasas";
String subStr = "as";
//统计subStr出现的次数
/*
* indexof(String sub,int index)
*/
int index = 0,count = 0;
while((index=str.indexOf(subStr, index))!=-1){
count++;
index += subStr.length();
}
System.out.println(count);
}
}
public class ZeroOneSort {
public static void main(String[] args) {
int[] ary = {0,1,1,0,1,0,1,0};
int index = 0;
for(int i=0;i<ary.length;i++){
if(ary[i]==0){
ary[i] = 1;
ary[index++] = 0;
}
}
System.out.println(Arrays.toString(ary));
}
}