java基础
笔记的都是需要背诵的零散知识点,以顺序的方式组织
文章目录
1.单例模式
- 静态方法和属性的经典实用
- 设计模式的理解:设计模式是在大量的实践中总结和理论化之后优选的代码结构,编程风格,以及解决问题的思考方式。设计模式就像是经典的棋谱,不同的棋局,我们用不同的棋谱,免去我们自己再思考和摸索
- 单例模式:
单例模式:就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法
单例模式两种方法:(1)饿汉式(2)懒汉式
2.饿汉式VS懒汉式
- 二者最主要的区别在于创建对象的实际不同:
饿汉式是在类加载就创建了对象实例
懒汉式是在使用时才创建 - 饿汉式不存在线程安全问题,懒汉式存在线程安全问题
- 饿汉式存在浪费资源的可能。因为如果程序员一个对象实例都没有使用,那么饿汉式创建的对象浪费了,懒汉式是在使用时才创建没救不存在这个问题
- 在我们javaSE标准中,java.lang.Runtime就是经典的单例模式
3.final关键字
- 常量,不希望被继承覆盖重写修改——final
- final 可以修饰、类、属性、方法、局部变量
- 程序员可能使用的场景需求:
(1)不希望类被继承时——final
(2)不希望父类的某个方法被子类覆盖/重写(override)时——final
案例【访问修饰符 final 返回类型 方法名】
(3)不希望类的某个属性的值被修改——final
案例【public final double TAX_RATE=0.08】
(4)不希望类的某个局部变量被修改——final
案例【final double TAX_RATE=0.08】
4.final小细节
(1)final修饰的属性又叫常量,XX_XX_XX命名
(2)final修饰的属性在定义时,必须赋初值,常量不能修改。
(3)常量赋值可以加在如下位置之一:
①定义时:public final double TAX_RATE=0.08
②在构造器中
③在代码块中
(4)类final了不能被继承,但是可以实例化对象
(5)如果类不是final类,但是含有final方法,虽然方法不能重写,但是可以被继承
(6)类已经是final类了,没必要再将方法修饰成final方法
(7)final和static往往搭配使用,效率更高,不会导致类加载。底层编译做了优化处理
(8)包装类(Integer,Double,Float,Boolean 等都是final)String也是final类
5.抽象类
- 当父类的一些方法不确定时,但是需要声明,可以用abstract关键字修饰,就是抽象方法
- 因为实现了没什么意义
- 抽象类:
(1)用abstract关键字来修饰一个类时,这个类就叫抽象类。
案例【访问修饰符 abstract 类名{ }】
(2)用abstract关键字来修饰一个方法时,这个方法就是抽象方法
案例【访问修饰符abstract返回类型方法名(参数列表);//没有方法体】
(3)抽象类的价值更多作用是在于设计,是设计者设计好后,让子类继承并实现抽象类()
(4)抽象类,是考官比较爱问的知识点,在框架和设计模式使用较多 - 抽象类细节:
(1)抽象类不能被实例化
(2)抽象类不一定要包含abstract方法
(3)一旦包含了abstract方法,则这个类必须声明为abstract类
(4)abstract只能修饰类和方法,不能修饰属性和其他的
(5)抽象类可以有任意成员,比如非抽象方法,构造器,静态属性等等
(6)抽象类本质还是类
(7)抽象方法不能有主体abstract void aaa();加花括号错
(8)如果一个类继承了抽象类,他必须实现抽象类的所有抽象方法,除非也声明为抽象类
(9)抽象方法不能使用private、final、static类修饰,因为这些是和重写相违背的
6.抽象类——模板设计模式
- 理解:抽象类体现的就是一种模板模式的设计,抽象类作为多个子类的通用模板,子类再抽象类得基础上进行扩展,改造,但子类总体上会保留抽象类的行为方式
- 模板设计能解决的问题
(1)当功能内部一部分实现是确定的,一部分实现是不确定的。这时可以把不确定的部分暴露出去,让子类去实现
(2)编写一个抽象父类,父类提供了多个子类的通用方法,并把一个或多个方法留给其子类实现,就是一种模板模式
6.接口
- 语法:
interface 接口名{
//属性
//抽象方法
}
class 类名 implements 接口{
//自己属性;
//自己方法;
//必须实现接口的抽象方法
}
- 接口理解:就是给出一些没有实现的方法,封装到一起,到某个类要使用的时候再根据具体情况把这些方法写出来
- 接口是更加抽象的抽象类
- 抽象类里的方法可以有方法体,接口里的所有方法都没有方法体
- 接口不能被实例化
- 接口中所有的方法是public方法,接口中抽象方法,可以不用abstract修饰:
void aaa();
实际上是: abstract void aa(); - 一个普通类实现接口,就必须将接口的所有方法的都实现
- 抽象类实现接口,可以不用实现接口的方法
- 一个类同时可以实现多个接口
- 接口中的属性,只能是final的,而且是public static final 修饰符
案例【int a=1;实际上 public static final int a =1;】 - 接口中属性的访问形式:接口名.属性名
- 接口中不能继承其他的类。但是可以继承多个别的接口
- 接口的修饰符 只能是public 和默认,这点和类的修饰符是一样的
7.接口继承比较
- 继承的主要价值在于:解决代码的复用和可维护性
- 接口的价值主要在于:设计,设计好各种规范(方法),让其他类去实现这些方法更加灵活
- 接口在一定程度上实现代码解耦
8.接口的多态性
- 多态参数,可以接收多种对象的参数
- 多态数组,
- 接口存在多态传递现象
9.内部类
- 一个类的内部又完整的嵌套了另一个类结构。被嵌套的类称为内部类(inner class),嵌套其他类的类称为外部类(outer class)。
- 类的五大成员是哪些?
[属性、方法、构造器、代码块、内部类] - 内部类最大的特点:就是可以直接访问私有属性,并且可以体现类与类之间的包含关系。(看底层源码时,有大量的内部类)
- 语法:
- 内部类的分类:
局部就是在成员的局部位置
10.局部内部类
- 位置:局部内部类是定义在外部类的局部位置,比如方法中
- 局部类有类名
- 可以直接访问外部类的所有成员,包含私有的
- 作用域:仅仅在定义他的方法或者代码块中
- 局部内部类---->访问---->外部类的成员【访问方式:直接访问】
- 外部类---->访问---->局部内部类的成员【访问方式:创建对象,在访问,必须在作用域内】
- 外部其他类-----不能访问----->局部内部类(因为局部内部类地位是一个局部变量)
- 如果外部类和局部内部类的成员重名时,默认遵循就近原则,如果想访问外部类的成员,则可以使用(外部类名.this.成员)去访问
11.匿名内部类
- 位置:匿名内部类是定义在外部类的局部位置,比如方法中,并且没有类名,且还是一个对象
- 语法:
- 理解:匿名内部类的语法比较奇特,是类又是对象,两者的特征都有
- 可以直接访问外部类的所有成员,包含私有的
- 不能添加访问修饰符,地位是局部变量
- 作用域:仅仅在定义他的方法或代码块中
- 匿名内部类----->访问----->外部类成员【访问方式:直接访问】
- 外部其他类---->不能访问---->匿名内部类(局部变量)
- 如果外部类和匿名内部类的成员重名时,匿名内部类访问的话,默认遵循就近原则,如果想访问外部类的成员,则可以使用(外部类名.this.成员)去访问
12.局部内部类VS匿名内部类区别
局部内部类和匿名内部类行为和能力差不多。局部内部类的名字在方法外是不可见的。匿名内部类用过一次就不在使用,而使用局部内部类的理由是,需要不止一个该内部类对象。
13.局部内部类匿名内部类只能final的局部变量?
首先,我们看一个局部内部类的例子:
class OutClass {
private int age = 12;
public void outPrint(final int x) {
class InClass {
public void InPrint() {
System.out.println(x);
System.out.println(age);
}
}
new InClass().InPrint();
}
}
这里有一个外部类OuterClass和一个内部类InClass,内部类访问了外部类的一个方法中的一个局部变量x,在这里,x必须是final的,否则会报错:
Cannot refer to a non-final variable x inside an inner class defined in a different method
追究其根本原因就是作用域中变量的生命周期导致的;
先需要知道的一点是:内部类和外部类是处于同一个级别的,内部类不会因为定义在方法中就会随着方法的执行完毕就被销毁.
这里就会产生问题:当外部类的方法结束时,局部变量就会被销毁了,但是内部类对象可能还存在(只有没有人再引用它时,才会死亡)。这里就出现了一个矛盾:内部类对象访问了一个不存在的变量。为了解决这个问题,就将局部变量复制了一份作为内部类的成员变量,这样当局部变量死亡后,内部类仍可以访问它,实际访问的是局部变量的”copy”。这样就好像延长了局部变量的生命周期。我们可以通过反编译生成的.class文件来实验:
在命令行窗口中先执行命令” javac OutClass.java”进行编译,会得到两个文件: OutClass$1InClass.class、OutClass.class:
javap是 Java class文件分解器,可以反编译,也可以查看java编译器生成的字节码。
这里我们可以再执行命令”javap -privateOutClass$1InClass”进行反编译,”-private”表示显示所有类和成员,执行后会得到如下结果:
可见方法中的局部变量实际上确实会复制为内部类的成员变量使用。
问题又出现了:将局部变量复制为内部类的成员变量时,必须保证这两个变量是一样的,也就是如果我们在内部类中修改了成员变量,方法中的局部变量也得跟着改变,怎么解决问题呢?
就将局部变量设置为final,对它初始化后,我就不让你再去修改这个变量,就保证了内部类的成员变量和方法的局部变量的一致性。这实际上也是一种妥协折中。
若变量是final时:
若是基本类型,其值是不能改变的,就保证了copy与原始的局部变量的值是一样的;
若是引用类型,其引用是不能改变的,保证了copy与原始的变量引用的是同一个对象。
这就使得局部变量与内部类内建立的拷贝保持一致。维持了数据的一致性。
java8中匿名/局部内部类访问局部变量时,局部变量已经可以不用加final了,但其实这个局部变量还是final的,只不过不用显式的加上而已,实际上是底层帮我们加上了。
14.成员内部类
-
位置说明:成员内部类是定义在外部类的成员位置,并且没有static修饰
-
可以一直间接访问外部类的所有成员,包含私有的
-
可以添加任意访问修饰符(public protected 默认 private)(成员)
-
作用域:和外部类的其他成员一样,为整个类体
-
成员内部类---->访问---->外部类成员(比如属性)【访问方式:直接访问】
-
外部类---->访问---->成员内部类【访问方式:创建对象,在访问】
-
外部其他类---->访问---->成员内部类
-
如果外部类和内部类的成员重名时,内部类访问的话,默认遵循就近原则,如果想访问外部类的成员,则可以使用(外部类名.this.成员)去访问
-
外部类访问方式:
第一种:编写一个方法,然后方法返回对象【间接】
第二种:类名称 对象名 =new 类名称();
外部类名称.内部类名称 对象名 = new 外部类名称().new 内部类名称();
15.静态内部类
- 位置说明:静态内部类是定义在外部类的位置上,并且有static修饰
- 访问都类似
- 可以直接访问外部类的所有今天成员,包含私有的,但不能直接访问非静态成员
- 可以添加任意访问修饰符(public、protected、默认、private)
- 作用域:同其他成员,为整个类
- 静态内部类---->访问---->外部类(比如静态属性)【访问方式:直接访问所有静态成员】
- 外部类----访问------->静态内部类【访问方式:创建对象,再访问】
- 外部其他类----->访问------>静态内部类
- 如果外部类和静态内部类的成员重名时,静态内部类访问的时,默认遵循就近原则,如果想访问外部类的成员,则可以使用(外部类名.成员)去访问