📄 05. core java note.txt
字号:
什么时候类加载
第一次需要使用类信息时加载。
类加载的原则:延迟加载,能不加载就不加载。
触发类加载的几种情况:
(1)、调用静态成员时,会加载静态成员真正所在的类及其父类。
通过子类调用父类的静态成员时,只会加载父类而不会加载子类。
(2)、第一次 new 对象的时候 加载(第二次再 new 同一个类时,不需再加载)。
(3)、加载子类会先加载父类。
注:如果静态属性有 final 修饰时,则不会加载,当成常量使用。
例:public static final int a =123;
但是如果上面的等式右值改成表达式(且该表达式在编译时不能确定其值)时则会加载类。
例:public static final int a = math.PI
如果访问的是类的公开静态常量,那么如果编译器在编译的时候能确定这个常量的值,就不会被加载;
如果编译时不能确定其值的话,则运行时加载
类加载的顺序:
1.加载静态成员/代码块:
先递归地加载父类的静态成员/代码块(Object的最先);再依次加载到本类的静态成员。
同一个类里的静态成员/代码块,按写代码的顺序加载。
如果其间调用静态方法,则调用时会先运行静态方法,再继续加载。同一个类里调用静态方法时,可以不理会写代码的顺序。
调用父类的静态成员,可以像调用自己的一样;但调用其子类的静态成员,必须使用“子类名.成员名”来调用。
2.加载非静态成员/代码块:
先递归地加载父类的非静态成员/代码块(Object的最先);再依次加载到本类的非静态成员。
同一个类里的非静态成员/代码块,按写代码的顺序加载。同一个类里调用方法时,可以不理会写代码的顺序。
但调用属性时,必须注意加载顺序。一般编译不通过,如果能在加载前调用,值为默认初始值(如:null 或者 0)。
调用父类的非静态成员(private 除外),也可以像调用自己的一样。
3.调用构造方法:
先递归地调用父类的构造方法(Object的最先);默认调用父类空参的,也可在第一行写明调用父类某个带参的。
再依次到本类的构造方法;构造方法内,也可在第一行写明调用某个本类其它的构造方法。
注意:如果加载时遇到 override 的成员,可看作是所需创建的类型赋值给当前类型。
其调用按多态用法:只有非静态方法有多态;而静态方法、静态属性、非静态属性都没有多态。
假设子类override父类的所有成员,包括静态成员、非静态属性和非静态方法。
由于构造子类时会先构造父类;而构造父类时,其所用的静态成员和非静态属性是父类的,但非静态方法却是子类的;
由于构造父类时,子类并未加载;如果此时所调用的非静态方法里有成员,则这个成员是子类的,且非静态属性是默认初始值的。
成员,包括变量和方法
成员变量,包括实例变量和静态变量
final 修饰符
(最终的、最后的)当final修饰时,不能被改变,不能被继承
1.final 可以用来修饰类、属性和方法、局部变量。
2.final 修饰一个属性时,该属性成为常量。
(1)对于在构造方法中利用final进行赋值时,此时在构造之前系统设置的默认值相对于构造方法失效。
(2)对于实例常量的赋值有两次机会
在初始化的时候通过声明赋值
在构造的时候(构造方法里)赋值
注:不能在声明时赋值一次,在构造时再赋值一次。
注意:当final修饰实例变量时,实例变量不会自动初始化为0;但必须给他赋值才能通过编译。
3.final 修饰方法时,该方法成为一个不可覆盖的方法。这样可以保持方法的稳定性。
如果一个方法前有修饰词private或static,则系统会自动在前面加上final。
即 private 和 static 方法默认均为 final 方法。
4.final 常常和 static、public 配合来修饰一个实例变量,表示为一个全类公有的公开静态常量。
例: public static final int a = 33;
在这种情况下属性虽然公开了,但由于是一个静态常量所以并不算破坏类的封装。
5.final 修饰类时,此类不可被继承,即final类没有子类。
一个 final 类中的所有方法默认全是final方法。
final 不能修饰构造方法,构造方法不能被继承更谈不上被子类方法覆盖。
关于 final 的设计模式:不变模式
1、不变模式:一个对象一旦产生就不可能再修改( string 就是典型的不变模式);
通过不变模式可以做到对象共享;
2、池化思想:用一个存储区域来存放一些公用资源以减少存储空间的开销。
有池的类型:boolean,byte,int,short,long,char,(池范围在-127~128之间)
(float,double 等小数没有池)
例:在String类中有个串池(在代码区)。
池:堆里的一片独立空间。目的是拿空间换时间,让运算效率更高。
(1)如果用Stirng str = “abc” 来创建一个对象时,则系统会先在“串池”中寻找有没有“abc”这个字符串
如果有则直接将对象指向串池中对应的地址,如果没有则在串池中创建一个“abc”字符串。
所以:String str1 = “abc”;
String str2 = “abc”;
Str1 == str2 返回值是ture;他们的地址是一样的。
也就是说str1和str2都指向了代码空间中相同的一个地址,而这个地址空间保存就是是字符串"abc"
字符串是不可改变的类型,所以可以共享。所以串池里不会有相同的两个字符串。
(2)如果用String str = new String("abc")则直接开辟一块内存放"abc"这个字符串。
所以上面这语句,创建两个"abc",一个在池,一个是对象
String str2 = new String("abc");
Str == str2 返回值是false;他们的地址是不一样的。
即是说str和str2分别指向了堆空间中不同的两个地址,而这两个地址空间保存的都是字符串"abc"
StringBuffer 类(java.lang下的)。
对于字符串连接
String str=”1”+”2”+”3”+”4”;
产生:
12 123 1234
这在串池中产生多余对象,而我们真正需要的只有最后一个对象,这种方式在时间和空间上都造成相当大的浪费。
所以我们应该使用 StringBuffer(线程安全的) 或者 StringBuilder(线程不安全的)来解决
解决方案:
StringBuffer sb = new StringBuffer(“1”);
Sb.append(“2”);
Sb.append(“3”);
Sb.append(“4”);
S = sb.toString();
解决后的方案比解决前在运行的时间上快2个数量级。
StringBuilder (1.5版本后出现的)
线程不安全的,在多线程并发时会出现问题。但仍是字符串合并的首选。
运行效率比 StringBuffer 快一倍。
abstract 抽象
1.可用来修饰类、方法
2.abstract 修饰类时,则该类成为一个抽象类。
抽象类不可生成对象(但可以有构造方法留给子类使用),必须被继承使用。
抽象类可以声明,作为编译时类型,但不能作为运行时类型。
abstract 永远不会和 private,static,final 同时出现。( 因为抽象必须被继承。)
3.abstract 修饰方法时,则该方法成为一个抽象方法,抽象方法不能有实现;由子类覆盖后实现。
比较:private void print(){};表示方法的空实现
abstract void print();表示方法为抽象方法,没有实现
4.抽象方法从某中意义上来说是制定了一个标准,父类并不实现,留给子类去实现。
注:抽象类中不一定要有抽象方法,但有抽象方法的类一定是抽象类。
抽象类可以有抽象方法和非抽象方法。实现抽象类的第一个具体类必须实现其所有抽象方法。
5.关于抽象类的设计模式:模板方法
灵活性和不变性
interface 接口
1、定义:接口不是类,而是一组对类需求的描述,这些类要遵从接口描述的统一格式进行定义。
定义一个接口用关键字 interface。
例:public interface a{……}
2、接口是一种特殊的抽象类。
在一个接口中,所有的方法为公开、抽象的方法,所有的属性都是公开、静态、常量。
所以接口中的所有属性可省略修饰符:public static final。也只能用这三个修饰符。
接口中所有的方法可省略修饰符:public abstract。但这些都是默认存在的。
3、一个类实现一个接口必须实现接口中所有的方法,否则其为一抽象类。而且实现类的方法需要 public
实现接口用关键字 implements.
所谓实现一个接口就是实现接口中所有的方法。
例:class Aimple implements A{……..};
4、一个类除了继承另一个类外(且只能继承一个类),还可以实现多个接口(接口之间用逗号分割)。
接口可以实现变相的多继承。
例:class Aimple extends Arrylist implements A,B,C{…}
5、不能用“new 接口名”来实例化一个接口,但可以声明一个接口。
6、接口与接口之间可以多继承。
例:interface face1 extends face2,face3{}
接口的继承相当于接口的合并
7、接口的作用
(1)、间接实现多继承。
用接口来实现多继承并不会增加类关系的复杂度。因为接口不是类,是在类的基础上的再次抽象。
父类:主类型 接口:副类型
典例:父亲(主) 和 老师(副)
(2)、允许我们为一个类定义出混合类型。
(3)、通过接口制定标准
接 口:标准的定义 定义标准
接口的调用者:标准的使用 使用标准
接口的实现类:标准的实现 实现标准
接口的回调:先有接口的使用者,再有接口的实现者,最后把接口的实现者的对象传到接口的使用者中,
并由接口的使用者通过接口来调用接口实现者的方法。
例:sun公司提供一套访问数据库的接口(标准),java程序员访问数据库时针对数据库接口编程。
接口由各个数据库厂商负责实现。
(4)、解耦合作用:采用接口可以最大限度的做到弱耦合,将标准的实现者与标准的制定者隔离
(例:我们通过JDBC接口来屏蔽底层数据库的差异)
8、接口的编程设计原则
(1)、尽量针对接口编程(能用接口就尽量用接口)
(2)、接口隔离原则(用若干个小接口取代一个大接口)
这样可以只暴露想暴露的方法,实现一个更高层次的封装。
9、注意点:
(1)、一个文件只能有一个 public 接口,且与文件名相同。
(2)、在一个文件中不能同时定义一个 public 接口和一个 public 类。
(3)、接口与实体类之间只有实现关系,没有继承关系;
抽象类与类之间只有继承关系没有实现关系。接口与接口之间只有继承关系,且允许多继承。
(4)、接口中可以不写 public,但在子类实现接口的过程中 public 不可省略。
接口 VS 抽象类
1、接口中不能有具体的实现,但抽象类可以。
2、一个类要实现一个接口必须实现其里面所有的方法,而抽象类不必。
3、通过接口可以实现多继承,而抽象类做不到。
4、接口不能有构造方法,而抽象类可以。
5、实体类与接口之间只有实现关系,而实体类与抽象类只有继承关系
抽象类与接口之间既有实现关系又有继承关系。
6、接口中的方法默认都是公开抽象方法,属性默认都是公开静态常量,而抽象类不是。
修饰符的使用情况:
(Y表可用;不写表示不可用)
修饰符 类 属性 方法 局部变量(所有局部变量都不能用修饰符)
public Y Y Y
protected Y Y
(default) Y Y Y
private Y Y
static Y Y
final Y Y Y Y
abstract Y Y
访问权限控制:
修饰符 同一个类 同一个包 (不同包)子类 其他包
public Y Y Y Y
protected Y Y Y
(default) Y Y
private Y
Object类
1、object类是类层次结构的根类,他是所有类默认的父类。
2、object类中的其中三个方法。
(1)、finalize()
当一个对象被垃圾收集的时候,最后会由JVM调用这个对象的finalize方法;
注意:这个方法一般不用,也不能将释放资源的代码放在这个方法里;只有调用C程序时,才可能要用到
(2)、toString()
存放对象地址的哈希码值。
返回一个对象的字符串表示形式。打印一个对象其实就是打印这个对象toString方法的返回值。
可以覆盖类的toString()方法,从而打印我们需要的数据。 Public String toString(){……}
(3)、equals(Object obj)
用来判断对象的值是否相等。前提是覆盖了equals方法。Object类中的equals方法判断的依然是地址
注意:String类已经覆盖了equals方法,所以能用equals来判断String对象的值是否相等。
下面是覆盖equals方法的标准流程:
/*************************************************************************/
public boolean equals(Object obj){
//第一步:现判断两个对象地址是否相等
if(this == obj) return true;
//第二步:如果参数是null的话直接返回false;
if(obj == null) return false;
//第三步:如果两个对象不是同一个类型直接返回false
if (getClass() != obj.getClass()) return false;
//?? if(!(this.getClass.getName().equals(o.getClass.getName())) return false;
//第四步:将待比较对象强转成指定类型,然后自定义比较规则
Student s = (Student) obj;
if(s.name.equals(this.name)&&s.age==this.age) return true;
else return false;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -