一、抽象
1、存在意义
似是而非的,像却又不是;具有某种特征,但不完整。
Animal仅是一种会吃会睡的对象,再无其他行为,不够具体,不够完整。程序是用来模拟现实世界,解决实际问题的,现实世界中存在的都是动物具体的子类对象,并不存在动物对象,所以,Animal不应该被独立创建成对象。
如何限制这种对象的创建?
2、抽象类定义
抽象类不一定有抽象方法,有抽象方法一定是抽象类
//abstract修饰类,此类不能new对象。
//被abstract修饰的类就是抽象类
//抽象类意为不够完整的类、不够具体的类,抽象类对象无法独立存在,即不能new对象
public abstract class Person {
//父类抽象
}
public class Teacher extends Person {
//子类继承
}
3、作用
1)可被子类继承,提供共性属性和方法
2)可声明为引用,更自然的使用多态。
3)抽象父类,可作为子类的组成部分,依附于子类对象存在,由父类共性+子类独有组成完整的子类对象。
4、抽象方法定义
//父类提供的方法很难满足子类不同需求,如不定义,则表示所有动物都不会吃、睡。如果定义,略显多余,多数会被子类覆盖。
//类似这种有必要声明,而没必要实现的方法,可以定义为抽象方法。
//被abstract修饰的方法就是抽象方法
//抽象方法只有方法声明,没有方法实现。
public abstract void eat(); //父类中的抽象方法
public abstract void sleep(); //abstract放在修饰符前后都可
5、原则
//1)如果一个类中存在抽象方法,那么这个类也要被定义成抽象类
//2)子类继承抽象类后,必须重写父类中所有的抽象方法,如果子类没有重写所有的抽象方法,那么子类也要被定义为抽象类
public void eat() { //子类重写
System.out.println("吃饭...");
}
public void sleep() {
System.out.println("睡觉...");
}
6、实例化与数组的关系
实例化与数组的关系
//抽象类可以被创建成数组,是因为数组本质上是一个引用的集合,并不立即需要具体的对象实例。
//而抽象类不能被实例化,是因为它们不完整,缺少某些方法的具体实现,需要子类来完成这些实现。
//实例化意味着创建一个具体对象,而抽象类由于缺少某些方法的实现,所以不能独立存在。但是,数组是一个容器,它不依赖于具体的对象实现,只与引用有关。
二、static静态
1、存在意义
1、共享性:静态属性是整个类共同持有的共享空间(只有一份),任何对象修改静态属性,都会影响其他对象对该属性的访问。因为它们访问的是同一个数据。
2、性能优化:由于静态方法不需要为每个对象创建实例,它们可以减少内存使用并提高性能,尤其是在创建大量对象开销较大的情况下。
2、静态属性定义
被static修饰的属性 - 静态属性
//实例属性是每个对象各自持有的独立空间,对象单方面修改,不会影响其他对象。
//共享性修改影响:静态属性是整个类共同持有的共享空间(只有一份),任何对象修改静态属性,都会影响其他对象对该属性的访问。因为它们访问的是同一个数据。
//生命周期:静态属性的生命周期与类相同,它在类加载时被初始化,并在程序运行期间保持存在,直到程序结束。
//全局访问:可以通过类名直接访问静态属性,而不需要创建类的实例。
//如何访问静态成员
类.属性 类.方法 优先 不需要对象的创建
public int a;//实例属性
public static int b;//静态属性
3、静态方法定义
被static修饰的方法 - 静态方法
//
//注意事项:
1)static的方法可以直接访问static的属性 - //静态方法允许直接访问静态成员;
2)非static的方法可以直接访问static的属性 - //非静态方法允许直接访问静态成员;
3)static的方法不能(直接)访问非static的属性 - // 静态方法不能直接访问非静态成员;
4)如果static的方法要访问非static的属性,需要先创建对象
5)静态方法中不允许使用this或super关键字
4、使用
//MyClass
public int a;
public static int b;
public static void test(){
System.out.println(b); //正确
System.out.println(MyClass.b); //类名.属性
System.out.println(a); //错误,静态方法不能直接访问非静态属性
MyClass aclass = new MyClass(); //创建对象访问
System.out.println(aclass.a);
}
//MyTest01
MyClass.b = 10; //类.属性 赋值
MyClass.test(); //类.方法
三、单例设计模式
1、存在意义
一个类的对象的实例只有一个,例如:
Sun
、God
2、定义
1)如果我们要让类在一个虚拟机中只能产生一个对象,我们首先必须将类的构造方法的访问权限设置为private;
2)调用该类的某个静态方法以返回类内部创建的对象;
//不能用new操作符在类的外部直接产生类的对象;
//静态方法只能访问类中的静态成员变量,所以,指向类内部产生的该类对象的变量也必须定义成静态的。
3、使用
//饿汉式 - 上来先创建对象 A
private static A a = new A(); //在类内部创建的对象,等着被调用
private A(){ // 1)私有的构造函数,防止了外部代码创建多个实例
}
//2)调用该类的某个静态方法以返回类内部创建的对象
public static A getObject(){ //
return a;
}
//懒汉式 - 什么时候需要什么时候创建对象 B
private static B b; //私有的静态成员变量,用于存储类的唯一实例
private B(){
}
public static B getObject(){
if(b == null){ //第一次调用时b为空,所以创建对象
b = new B();
}
return b; //后续调用时,直接返回b,即上一次创建的对象
}
public class SingleObject {
private static SingleObject obj; //私有的静态成员变量,用于存储类的唯一实例
private SingleObject(){ // 私有的构造函数,防止了外部代码创建多个实例
}
public static SingleObject getObject(){ //获取单例对象的唯一方式
if (obj == null){
obj = new SingleObject();
}
return obj;
}
}
//测试方法
//饿汉式
//2)调用该类的某个静态方法以返回类内部创建的对象;
A obj1 = A.getObject(); //获取返回值
A obj2 = A.getObject();
System.out.println(obj1 == obj2); //true
//懒汉式
SingleObject obj1 = SingleObject.getObject();
SingleObject obj2 = SingleObject.getObject();
System.out.println(obj1 == obj2);
//true证明两个引用指向同一个对象,符合一个类的对象只能有一个
四、final
修饰
1、存在意义
final - 最终的,最后的 - 可以修饰变量(局部变量、属性)、方法、类
常见的类
String Math System
2、定义
//修饰类,最终的类,无法被继承
public final class Teacher {
//实例常量不再提供默认值,必须手动赋予初始值;
public final int A = 10;
//静态常量不再提供默认值,必须手动赋予初始值;
public final static int B = 10;
//0 正常的属性是有默认值的
public int c;
//修饰方法,最终的方法,无法被重写
final public void teach() {
}
}
//常量 - 值不能被修改
//常量的命名规范 XXX_YYY_ZZZ
System.out.println(Math.PI);
System.out.println(Math.E);
//main方法
//t1里面存的是地址,final修饰引用类型,地址不可变。
final Teacher t1 = new Teacher();
//地址不可变,就不能给t1重新赋值其他的地址
//t1 = new Teacher();
System.out.println("t1.c = " + t1.c); // c默认0
//final修饰的对象,对象本身的内容可以修改
t1.c = 100;
System.out.println("t1.c = " + t1.c); // 100
四、代码块
动态代码块可为实例属性赋值,或必要的初始行为。
静态代码块可为静态属性赋值,或必要的初始行为。
1、动态代码块
//定义在类中,与属性和方法处于同一级。(创建一次,执行一次)
class 类名 {
{
//动态代码块
}
}
//创建对象时,触发动态代码块的执行(创建一次,执行一次)。
执行时机:
//动态代码块和实例属性的初始化顺序,由在类中书写的顺序决定
//代码块和属性的初始化先于构造方法执行。
2、类加载
JVM
首次使用某个类时,查找到该类的.class
文件,将.class
文件中对类的描述信息(如:包名、类名、父类、属性、方法、构造方法)加载到内存中,进行保存。
- 创建对象;
- 创建子类对象;
- 访问静态属性;
- 调用静态方法;
- 主动加载:
Class.forName("全类名")
3、静态代码块
//定义在类中,与属性和方法处于同一级。(仅一次)
class 类名 {
static {
//静态代码块
}
}
//类加载时,触发静态代码块的执行(仅一次)。
执行时机:
//静态代码块和静态属性的初始化顺序,由在类中书写的顺序决定;
//代码块和属性的初始化先于构造方法执行。
4、执行顺序
//代码块和属性的执行顺序和在类中定义的顺序有关。
父类静态属性
父类静态代码块
子类静态属性
子类静态代码块 //静态优先非静态
父类实例属性 //父类优先子类
父类动态代码块
父类构造方法...
子类实例属性 //属性和代码块 优先构造方法
子类动态代码块
子类构造方法...