接口,重写父类的方法,重载
1. 默认方法:抽象类有默认的方法实现;java8之前接口不存在方法的实现。
2. 实现方法:extends来继承抽象类,若字类不是抽象的则需实现抽象类中声明的方法;接口的话,子类用implements来实现接口,需要实现接口定义的所有方法。
3. 构造器:抽象类可以有构造器;接口不能。
4. 和正常类的区别:抽象类不能被实例化;接口与类的类型不同。
5. 访问修饰符:抽象方法:public, protected. default等修饰符
接口:默认是public,不能使用其他
6. 多继承:抽象类一个字类只能有一个父类;接口的话一个字类能实现多个接口
7. 添加新方法:抽象类的子类中的代码可以不更改;接口则必须在子类中实现新方法。
1. 抽象类不能被实例化
2. 抽象类不一定有抽象方法,但是有抽象方法的类一定是抽象类
3. 抽象方法只声明就好,不需要在抽象类中实现
4. 构造方法,类方法(用static修饰的方法)不能声明为抽象方法
5. 抽象类的子类只有两个选择:继续抽象或者实现父类的抽象方法
1. 对象一旦被创建就无法改变,任何对他的改变都只会产生一个新的对象
2. 不可变对象的类即不可变类,如String, 基本类型的包装类, BigInteger, BigDecimal等
3. 不可变类应该被声明为final,或者使用静态工厂并声明构造器为private;
如果成员属性是可变对象属性,不要使这些对象改变
1. 获得类的实例的最简单的方法就是new,通过构造器来实现对象的创建。但不通过new,而是通过静态方法来创建类的实例对象,这就是静态工厂方法。
2. 相比于new来实例,静态工厂方法是有名字的:newInstance, valueOf, getInstance...
3. 相比于new来实例,静态工厂方法不用每次被调用时都创建新对象(单例模式)
4. 相比于new来实例,静态工厂方法可以返回原返回类型的子类
5. 相比于new来实例,静态工厂方法在创建带泛型的实例时能够使代码简洁
Map map = new HashMap(); F
Map map = new HashMap<>(); T
6. 静态工厂方法可以创建参数一样但是名称不一样的工厂方法, 例如:
class Child{
int age;
int weight;
public Child(int age, int weight){
this.age = age;
this.weight = weight;
}
public Child(int age){
this.age = age;
}
}
此时如果需要加入参数只有weight的构造方法显然会报错,因为和第二个构造方法的参数类型一样,会被认为是两个一样的构造器
如果用静态工厂方法:
class Child{
int age;
int weight;
public static Child newChild(int age, int weight){
Child c = new Child();
c.age = age;
c.weight = weight;
return c;
}
public static Child newChildWithAge(int age){
Child c = new Child();
c.age = age;
return c;
}
public static Child newChildWithWeight(int weight){
Child c = new Child();
c.weight = weight;
return c;
}
}
7. 静态工厂方法能减少对外的暴露
比如类Player:
class Player{
public static int NUM_SWIMMER = 1;
public static int NUM_RACER = 2;
public static itn NUM_RUNNER = 3;
protected int type;
public Player(int type){
this.type = type;
}
}
此类若只想让调用者传入的参数只在1,2,3里面选显然不可能
如果用静态工厂方法将构造方法让外面看不见:
class Player{
public static int NUM_SWIMMER = 1;
public static int NUM_RACER = 2;
public static itn NUM_RUNNER = 3;
protected int type;
private Player(int type){
this.type = type;
}
public static Player newRunner(){
return new Player(NUM_RUNNER);
}
...
}
静态方法将构造器隐藏起来只提供给静态方法使用,而外部需要创建Player的时候只能使用静态构造方法
1. 静态变量能直接使用类名来使用,而动态变量必须要先实例
2. 静态变量加static
3. 静态变量储存在方法区,属于类所有。实例变量则储存在堆当中
1. 获取Class对象的三种反射:
1. Class class1 = Class.forName("com.reflection.User");
2. Class class2 = User.class;
3. User user = new User();
Class class3 = user.getClass();
2. 获取对象实例的两种方法:
1. user1 = (User)class1.newInstance();
user1.setName("a");
user1.setAge("15");
2. Constructor constructor = class2.getConstructor(String.class, Integer.class);
user2 = (User)constructor.newInstance("b", 11);
1. new:高耦合
先查看new后面的类型,再决定分配多大的内存空间
调用构造函数,填充对象的各个域
构造方法返回后一个对象创建完毕,把他的引用地址发布到外部
2. 反射机制
3. clone(不会调用构造函数):不是复制地址,而是创建新的对象
分配内存
使用原对象的各个域来填充新对象的各个域
4. 使用反序列化(不会调用构造方法)
所谓序列化就是把对象通过流的方式存储到文件里面(此对象必须先重写Serializable接口)
那么反序列化也就是把字节内容读出来并还原成java对象,这里还原的过程就是反序列化
ObjectOutputStream obji = new ObjectOutputStream(new FileOutputStream("Object1.txt"));
Teacher teacher = new Teacher();
teacher.setName("张三");
teacher.setAge(20);
obji.writeObject(teacher);
//此时序列化结束,把新建的teacher对象放入了Object1.txt中
ObjectInputStream Obji = new ObjectInputStream(new FileInputStream("Object1.txt"));
Teacher t =(Teacher) Obji.readObject();
System.out.println(t.getName()+t.getAge());
//此时反序列化结束,此处的t即为通过反序列化建立的对象
a=a+b不会强制转换类型
a+=b回自动转换类型
例如:
byte a = 127;
byte b = 127;
b = a+b; //error: cannot convert from int to byte
b += a; //OK
short s1 = 1;
s1 = s1+1; //error: short类型变量在计算的时候会把类型转换为int
s1 += 1; //OK
1. &既可以是位运算符也可以是逻辑运算符; &&是逻辑运算符
2. &&有短路特性
1. final是一个修饰符,可以修饰变量,方法和类。final修饰意味着在初始化之后就不能再修改了。
2. finalize是在对象被回收之前调用的方法,给对象最后一个复活的机会。
3. finally是与try和catch一起使用的处理异常的方法。
首先要知道的是GC只能对堆区内的进行清理,而对于永久带不能进行GC
JVM堆内存的结构
Java的堆内存分为:Permanent Space和Heap Space,GC主要针对的是Heap Space
Heap Space又分为New Generation Area和 Old Generation Area
在年轻代使用的是Minor GC, 在老年代使用的是Full GC
在年轻代又分为Eden, Survivor(form), Survivor(to)
GC的具体流程
1. 新对象产生需要一定内存,执行内存空间的申请
2. 首先判断Eden区是否有内存空间,若此时Eden区空间充足则直接将对象放入Eden区
3. 若Eden区空间不够用,则自动执行Minor GC来释放空间,将Eden区的垃圾清理掉。这时候再判断Eden区空间够不够,如果够则直接再Eden区进行空间分配。
4. 若Minor GC后的Eden区空间依然不足,则堆Survivor区进行判断,如果Survivor区空间足够则将Eden区域的活跃对象放入Survivor区域,然后在判断Eden区是否充足。如果Eden区空间充足就进行空间分配。
5. 如果此时Survivor区也没有空间了,则区判断老年区空间是否足够,如果足够则将Survivor区的活跃对象放入老年区,那么Survivor区就有空间了,然后Eden区就有空间了,然后就可以在Eden区创建对象了。
6. 若老年区的空间不足了,则堆老年代执行Major GC(Full GC)。若GC后老年区空间够了,就把Survivor的活跃对象移到老年代,然后Survivor空间就够了,然后Eden的空间也够了,然后就能在Eden区建立新的对象了。
7. 若经过Full GC之后老年代空间依然不足,则此时抛出OOM异常
GC与finalize方法
GC中finalize的执行流程:
1. fianliaze方法是在对象被GC回收了的时候, 且此对象重写了finalize方法,则系统给它的一个复活的机会
2. 当一个对象在被判断为不可达的时候(可达性分析),GC会判读该对象是否重写了fianlize方法,若没有则直接回收。
3. 若该对象重写了finalize方法,且没有执行过finalize方法则将其放入F-Queue队列。
4. 让一个低优先级的线程去执行finalize方法
5. 执行finalize方法之后再去进行可达性判断,如果还是不可达就清理掉。否则进行复活。
GC中finalize的执行流程:
基础状态说明:
终结状态空间:
unfinalized:新建的对象会先进入此状态,GC并未准备清理该对象,也自然不会执行fianlize方法,此时对象可达
finalizable:标识GC可以对该对象执行finalize方法。此时GC已经检测到了此对象不可达。
finalized:标识GC已经对该对象执行过了finalize方法
可达性状态空间:
reachable: 表示GC Roots引用可达
finalize-reachable:表示不是reachable但是通过某个finalize之后可达
unreachable:表示对象肯定不可达了
finalize执行时状态变迁过程:
1. 对象刚建立:reachable , unfinalized
2. 程序运行之后:f-reachable或unreachable
3. JVM检测到这个对象已经不可达了,则将他的终结状态改为finalizable,表示可以执行finalize方法,再不执行就要被回收了
4. 在某个时刻,JVM拿出finalizable对象,将其标记为finalized并执行finalize方法。由于在活动线程中引用了该对象,所以该对象的状态变成了reachable, finalized。该动作将影响某些其他对象的状态也变成reachable
5. 若JVM检测到finalized状态的对象变成unreachable则可以直接将其回收
6. 若对象未覆盖finalize方法JVM也可以直接将其回收
引自 https://blog.csdn.net/baiye_xing/article/details/71788741
1.引用拷贝:
Teacher teacher = new Teacher("Taylor",26);
Teacher otherteacher = teacher;
System.out.println(teacher);
System.out.println(otherteacher); //此处的两个输出是一样的(地址)
对象拷贝
Teacher teacher = new Teacher("Swift",26);
Teacher otherteacher = (Teacher)teacher.clone();
System.out.println(teacher);
System.out.println(otherteacher); //此处输出的结果不同(地址)
public class ShallowCopy {
public static void main(String[] args) throws CloneNotSupportedException {
Teacher teacher = new Teacher();
teacher.setName("Delacey");
teacher.setAge(29);
Student2 student1 = new Student2();
student1.setName("Dream");
student1.setAge(18);
student1.setTeacher(teacher);
Student2 student2 = (Student2) student1.clone();
System.out.println("拷贝后");
System.out.println(student2.getName());
System.out.println(student2.getAge());
System.out.println(student2.getTeacher().getName());
System.out.println(student2.getTeacher().getAge());
System.out.println("修改老师的信息后-------------");
// 修改老师的信息
teacher.setName("Jam");
System.out.println(student1.getTeacher().getName());
System.out.println(student2.getTeacher().getName());
}
}
class Teacher implements Cloneable
{
private String name;
private int age;
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public int getAge()
{
return age;
}
public void setAge(int age)
{
this.age = age;
}
}
class Student2 implements Cloneable
{
private String name;
private int age;
private Teacher teacher;
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public int getAge()
{
return age;
}
public void setAge(int age)
{
this.age = age;
}
public Teacher getTeacher()
{
return teacher;
}
public void setTeacher(Teacher teacher)
{
this.teacher = teacher;
}
@Override
public Object clone() throws CloneNotSupportedException
{
Object object = super.clone();
return object;
}
}
此时两个student所引用的teacher是一个,所以对teacher进行修改的时候会对两个student都产生影响。
2.2 深拷贝
public class DeepCopy {
public static void main(String[] args) throws Exception
{
Teacher2 teacher = new Teacher2();
teacher.setName("Delacey");
teacher.setAge(29);
Student3 student1 = new Student3();
student1.setName("Dream");
student1.setAge(18);
student1.setTeacher(teacher);
Student3 student2 = (Student3) student1.clone();
System.out.println("拷贝后");
System.out.println(student2.getName());
System.out.println(student2.getAge());
System.out.println(student2.getTeacher().getName());
System.out.println(student2.getTeacher().getAge());
System.out.println("修改老师的信息后-------------");
// 修改老师的信息
teacher.setName("Jam");
System.out.println(student1.getTeacher().getName());
System.out.println(student2.getTeacher().getName());
}
}
class Teacher2 implements Cloneable {
private String name;
private int age;
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public int getAge()
{
return age;
}
public void setAge(int age)
{
this.age = age;
}
@Override
public Object clone() throws CloneNotSupportedException
{
return super.clone();
}
}
class Student3 implements Cloneable {
private String name;
private int age;
private Teacher2 teacher;
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public int getAge()
{
return age;
}
public void setAge(int age)
{
this.age = age;
}
public Teacher2 getTeacher()
{
return teacher;
}
public void setTeacher(Teacher2 teacher)
{
this.teacher = teacher;
}
@Override
public Object clone() throws CloneNotSupportedException
{
// 浅复制时:
// Object object = super.clone();
// return object;
// 改为深复制:
Student3 student = (Student3) super.clone();
// 本来是浅复制,现在将Teacher对象复制一份并重新set进来
student.setTeacher((Teacher2) student.getTeacher().clone());
return student;
}