1.9日学习笔记
类变量/静态变量
(jdk8以后,静态变量存放在堆里这个类对应的class对象最后,jdk8以前,静态变量存放在方法区)
类变量也叫静态变量/属性,是该类所有对象共享的变量,任何一个该类对象去访问它时,取到的都是相同的值,同样任何一个该类的对象去修改他时,修改的也是同一个变量。
static类变量,在类加载的时候就生成了。(new的时候加载)即使没有创建对象,只要类加载就可以使用类变量
语法:访问修饰符 static 数据类型 变量名;
如何访问类变量:类名.类变量名(推荐) 或 对象名.类变量名(静态变量的访问修饰符的访问权限和范围和普通属性是一样的)
当需要让某个类所有对象都共享一个变量时,就可以考虑使用类变量
类变量是该类的所有对象共享的,而实例变量是每个对象独享的。
加上static称为类变量或静态变量,否则称为实例变量/普通成员变量/非静态变量/普通属性
实例变量不能通过:类名.类变量名访问。
类变量的生命周期随类的加载开始,伴随类的消亡毁灭
当方法使用了static修饰后,该方法就是静态方法,只能访问静态属性/变量
类方法和普通方法都是随类的加载而加载,将结构信息存储在方法区:类方法中不允许使用和对象有关的关键字如:super和this关键字。
普通方法中隐含着this参数
普通方法和对象有关,需要通过对象名调用,不能通过类名调用。
普通方法既可以访问非静态成员也可以访问静态成员。
Main方法
main方法java虚拟机调用
jvm虚拟机需要调用类的main方法,所以该方法的访问权限必须是public
java虚拟机在执行main()方法时不必创建对象,所以该方法必须是static
该方法接受String类型的数组参数,该数组中保存执行Java命令时,传递给所运行的类的参数
在main方法中,可以直接调用main方法所在类的静态方法或静态属性。但是不能直接访问该类的非静态成员,必须创建该类的一个实例对象后,才能通过这个对象去访问类中的非静态成员。
代码块
代码化块又称为初始化块,属于类中的成员(即是类的一部分)类似于方法,讲逻辑语句封装在方法体中,通过{}包围起来。但和方法不同,没有方法名,没有返回,没有参数,只有方法体,而且不用通过对象或类显示调用,而是加载类时,或创建对象时隐式调用。
语法:[修饰符]{代码};
修饰符可选,要写的话也只能写static;代码块分两类,一类时用static修视的叫静态代码块;一类没有修饰符,叫普通代码块;逻辑语句可以为任何(输入、输出、方法调用、循环、判断等);其中 " ;" 可以写也可以省略;
相当于是另外一种形式的构造器(对构造器的补充机制)可以做初始化的操作;如果多个构造器中都有重复的语句,可以抽取到初始代码块中,提高代码的重用性。
当不管调用哪个构造器创建对象,都会先调用代码块的内容。
static代码块也叫静态代码块,作用就是对类进行初始化,而且它随着类的加载而执行,并且只会执行1次。如果是普通代码块,每创建1个对象,就会执行1次。
普通代码块,在创建对象时会被隐式的调用。如果只是使用类的静态成员时,普通代码块不会执行。(普通代码块是构造器的补充)
静态代码块先于构造器加载。
创建一个对象时,在一个类调用的顺序:
- 调用静态代码块和静态属性初始化(静态代码块和静态属性初始化调用的优先级一样,如果有多个静态代码块和多个静态变量初始化,则按他们定义的顺序调用)
- 调用普通代码块和普通属性的初始化(普通代码块和普通属性初始化调用的优先级一样,如果有多个普通代码块和多个普通属性初始化,则按定义顺序调用)
- 调用构造方法
构造方法(构造器)的最前面其实隐含了super()和调用普通代码块,静态相关的代码块,属性初始化,在类加载时,就执行完毕。因此优先于构造器和普通代码块执行的
当创建一个子类时,他们的静态代码块,静态属性初始化,普通代码块,普通属性初始化,构造方法的调用顺序:
- 父类的静态代码块和静态属性(优先级一样,按定义顺序执行)
- 子类的静态代码块和静态属性(优先级一样,按定义顺序执行)
- 父类的普通代码块和普通属性初始化(优先级一样,按定义顺序执行)
- 父类的构造方法
- 子类的普通代码块和普通属性初始化(优先级一样,按定义顺序执行)
- 子类的构造方法
静态代码块只能调用静态成员(静态属性和方法),普通代码块可以调用任意成员
类的加载
创建对象实例时;创建子类对象实例时,父类也会被加载;使用类的静态成员时(静态属性、方法);都会执行代码块。
单例设计模式
采取一定的方法保证在整个的软件系统中,对一个类只能存在一个对象实例,并且该类只提供1个取得其对象实例的方法。
单例模式有两种方式:1、饿汉式(有可能没使用到对象但是随类的加载会被创建(一开始就定义static 对象名=new 类名()));2、懒汉式(在程序运行过程中,只能创建一个对象,先定义一个静态static对象,但不初始化;在定义一个公共静态方法,初始化并返回一个对象);
步骤:1、将构造器私有化->防止直接new;2、类的内部创建对象;3、向外暴露一个静态的公共方法(getInstance(),返回对象)
饿汉式和懒汉式:
- 主要区别在于创建对象时机不同:饿汉式是在类加载就创建了对象实例,而懒汉式是在使用时才创建。
- 饿汉式不存在线程安全问题,懒汉式存在线程安全问题。
- 饿汉式存在浪费资源的可能。因为如果程序员一个对象实例都没有使用,那么饿汉式创建的对象就浪费了,懒汉式是使用时才创建,就不存在这个问题。
Runtime就是典型的单例模式
Final关键字
final可以修饰类、属性、方法、局部变量。
当不希望类被继承,可以用final修饰;当不希望父类的某个方法被子类覆盖/重写(override)时,可以用final关键字修饰;当不希望类的某个属性的值被修改时,可以用final修视;当不希望某个局部变量被修改时,可以使用final修饰。
final修饰的属性又叫常量,一般 用xx_xx_xx来命名;
final修饰的属性在定义时,必须赋初值,并且以后不能再修改,赋值可以在如下位置之一选择一个:(定义时,在构造器中,在代码块中)
如果final修饰的属性时静态的,则初始化的位置只能是:(定义时,在静态代码块 )不能在构造器中赋值
final类不能继承,但是可以实例化对象
如果类不是final类,但是含有final方法,则该方法虽然不能重写,但是可以被继承
一般来说,如果一个类已经是final类了,就没有必要再将方法修饰成final方法。
final不能修饰构造方法。
final往往与static搭配使用,效率更高,不会导致类加载,底层编译器做了优化处理
包装类(Integer、Double、Float、Boolean等)、String都是final类。
抽象类
当父类的某些方法需要声明,但是有不确定如何实现,可以用abstract关键字将其声明为抽象方法,那么用abstract来修饰该类就是抽象类。
父类的抽象方法,子类实现。
语法:访问修饰符 abstract 类名{}
用abstract关键字修饰一个方法时,这个方法就是抽象方法。语法:访问修饰符 abstract 返回类型 方法名(参数列表);//没有方法体
抽象类的价值更多在于设计,设计者设计好后,让子类继承并实现抽象类
抽象类不能实例化
抽象类不一定要包含abstract方法,也就是说抽象类也可以没有abstract方法
一旦类包含了abstract方法,则这个类必须声明为abstract。abstract只能修饰类和方法,不能修饰属性和其他的。
抽象类可以有任意成员(因为抽象类还是类),比如:非抽象方法、构造器、静态属性等
抽象方法不能有主体;
如果一个类继承了抽象类,则它必须实现抽象类的抽象方法,除非它自己也声明为abstract类。
抽象方法不能使用private、final、static来修饰,因为这些关键字都是和重写相违背。
模板设计模式
写一个模板类,再写其他子类继承该模板类。
接口
接口就是给出一些没有实现的方法,封装到一起,到某个类要使用的时候,再根据具体情况把这些方法写出来。
语法: interface 接口名{ //属性 //方法}
class 类名 implements 接口{ //自己属性; //自己方法; // 必须实现的接口的抽象方法}
jdk7.0以前 接口里的所有方法都没有方法体,即都是抽象方法。jdk8.0以后接口类可以有静态方法,默认方法,也就是说接口中可以有方法的具体实现。
接口不能被实例化,接口中所有的方法是public方法,接口中抽象方法可以不用abstract修饰,public也可以不用修饰。
一个普通类实现接口,就必须将该接口的所有方法都实现,可以使用alter+enter来解决
抽象类去实现接口时,可以不实现接口的抽象方法。
一个类可以同时实现多个接口,接口中的属性只能是final的,而且是public static final 修饰符。
接口中属性的访问形式: 接口名. 属性名
一个接口不能继承其他的类,但是可以继承多个别的接口
接口的修饰符,只能是public和默认
普通类实现接口时,就拥有了接口类的属性和方法(类似继承)
- 继承的价值:解决代码的复用性和可维护性
- 接口的价值:设计,设计好各种规范方法,让其它类去实现这些方法
- 接口比继承更加灵活,继承是满足 is-a 的关系,而接口只需满足 like -a 的关系
- 接口在一定程度上实现代码解耦(即:接口规范性+动态绑定)
接口的多态特性:
多态参数,多态数组,接口存在多态传递现象:接口类型的变量可以指向实现了该接口的类的对象的实例。
若出现继承的父类和实现的接口有相同的属性,则要明确指出访问的是哪个(super.属性 或 接口名.属性)