王道Java40th笔记(0403)
基础知识
全限定类名
包含包名的方法名全称;防止因为类名重复,编译器就近原则选择错方法
转义字符
/b
退格
/t
Tab
nextLine
nextLine()
后面不要使用next*()
会导致读取错误
foreach
for(ElemType et:容器名)
Java仅有值传递
- 值传递:方法接收的不是实参本身,而是实参一个拷贝;因此方法是不能对实参做出修改
- 引用传递:方法接收就是实参本身(实参的地址),不是拷贝对象,方法是可以对实参做出修改
注解
@Override
: 限定某个方法,是重写父类方法, 编译检查
@Deprecated
: 用于表示某个程序元素(类, 方法等)已过时
@FunctionalInterface
:功能接口
@SuppressWarnings
: 抑制编译器警告
Random 特性
左闭右开[ )
优先级提升
// 三元运算符为一个整体,混合运算优先级以最高的为准
Object obj = true?new Integer(1):new Double(2);
System.out.println(obj); // 1.0 Integer --> Double
final byte a = 1;
final byte b = 2;
byte c = a + b; // 编译通过,a,b为常量,类型不提升
byte d = a + c; // 编译不通过,c为变量,右侧运算类型为int
类
类的成员
属性(成员变量),方法,构造器,代码块,内部类
默认的初始化
- 基本数据类型作为
类成员
的时候,即使没有进行初始化。Java也会给定默认的初始值- 局部变量没有默认值,需要依靠手动初始化
内存分布
基本数据类型,局部变量 --- 栈帧
引用数据类型---栈帧(引用)+堆(对象)
栈 --- 局部变量 --- 没有默认值,需要初始化才可用
堆 --- 存储对象 --- 在初始化前就有了默认值(即使指定赋值非空,也先赋默认值
null
,再赋指定值)
类加载
- 过程:加载 --> 连接(默认赋值) --> 初始化
- 在创建对象
new
前,会类加载(类加载的一部分【加载,连接】)- 访问类的静态成员
类名.静态成员
前,会类加载- 启动
main
方法前也会对main所在的类进行类加载子类
的类加载会触发父类
的类加载;先父后子
子类名.父类静态成员
不进行子类的类加载- 创建子类对象时,不会连带创建父类对象,父类的成员会创建在子类对象(堆)的专门区域里,
super
指向这块区域- 类加载
仅加载一次
,无论之后是否创建对象,调用方法,都不会再进行类加载- 类加载,执行带有
static
的语句和代码块,连接
时对静态成员初始化,与显示初始化语句无关- 基本数据类型 和 String 的
全局常量static final
调用不触发类加载(不在类的静态常量池中)
构造器(是类就有)
- 用来赋值初始化,而不是创建对象
- 赋值顺序:默认值赋值--> 显示初始值赋值 --> 构造器形参赋值
this(参数1,参数2,...)
显示调用对应参数的构造器,仅能够在构造器内的 第一行 ,调用一次;super
同样
this
Student s = new Student();
对象名.成员方法
隐含形参this
,默认传递引用s
静态成员方法不含
this
如果调用成员方法,需要手动对象实例化
Super
不是引用,但可以当父类引用使用,指向子类对象的一片特殊区域
成员变量的赋值
- 静态成员变量在类加载时初始化(默认赋值 --> 显示赋值)
- 成员变量在创建对象时由构造代码块和构造器赋值
- 类加载先于对象的创建,因此静态成员初始化早于成员变量
- 赋值顺序一般是:默认值赋值-->显示赋值/构造代码块赋值-->构造器赋值
- 构造代码块赋值 与 显示赋值 顺序执行
代码块
- 构造代码块:在构造器调用时执行;在显示赋值,构造代码块同时存在时--顺序执行(块内不能使用
this
调用构造器)
- 仅可以给成员变量赋值,块内定义的变量是局部变量,不是成员
- 类加载不执行,new执行
- 应用:提取出构造器的公共语句,写入构造代码块 -- 编译自动添加到每个构造器中
- 静态代码块:在类加载时执行
- 应用:用于给类的静态成员赋值,调用一次的方法,测试类加载
访问权限修饰符
用来限定类和类的成员
- private :只能够在同一类中能够访问,私有的,外面谁都不能用。
- 默认(缺省):同一包中的子类或者其它类能够访问,同包中都可以使用。
- protected :
不同包
的子类能够通过创建子类对象
访问父类,同包
可任意访问。
- 不同包的子类,只有创建
子类自身对象
,才可以访问父类成员- 目的:防止滥用,仅仅提供给子类使用
- public :没有限制
继承的特性
关系:子类
is-a
父类
子类名.父类静态方法
访问父类静态方法子类的类加载会触发父类的类加载,并且类加载的顺序是
先父后子
类对象创建的过程中,父类的构造方法会被调用,但是不会创建父类的对象
子类构造器隐含
super();
子类对象中会专门开辟一片独立的区域,用来存储父类的成员变量
super
、this
两个关键字在表示调用构造器时,不能共存子类含有父类同名成员,父类同名成员会被隐藏,可用
super
调用静态成员变量,没有继承关系;父子类同名静态成员有各自的存储空间,互不干涉
默认直接继承
Object
,一旦手动继承了其他类,则变成了间接继承了Object
即继承类直接继承Object
(如果继承类没有显示继承其他类的时)子类 与 父类 有同名成员变量 父类
变量被隐藏
,有同名成员方法 父类方法被覆盖
;但都可以使用super
来调用
对象名.成员变量
的范围和值,都由引用
的数据类型来决定,因为编译器只能看引用,对象要在创建时进行类加载才可显示对象名.方法名
的范围和调用结果,是根据new
对象的实际类型 来决定的(多态)[编译看左,运行看右]
子类重写的限制
- 保持一致 : 方法名,形参列表
- 保持兼容:访问权限等级,返回值类型(引用类型)
重写 & 重载
方法重载Overload | 方法重写Override | |
---|---|---|
类 | 同类中 | 父子类 |
方法名 | 相同 | 相同 |
参数列表 | 不同 | 相同 |
访问权限 | 不影响 | 子类方法的访问权限 >= 父类访问权限 |
返回类型 | 不影响 | 引用类型保持兼容 |
构造方法,静态方法,私有方法,final方法 -- 不能重写
多态
- 条件:存在继承,方法重写,父类引用指向不同子类对象
- 特征:父类引用,指向不同子类,不同子类重写了同名方法,调用这个会产生不同效果
- 区分:父子类存在同名成员变量,表现出属性的隐藏
- 父类引用不能直接调用
子类特有
的方法,需要强转为子类引用再调用- 强制向下转型的条件:父类(PA)的引用指向子类对象(A),那么只能转为子类(A)引用,而不能强转为兄弟姐妹的引用(B,C ...)
- 需要使用
if(引用名 instanceof 类名/接口名)
判断,保障向下转型安全性
final
修饰的类不能被继承
修饰的方法不能被重写
修饰的基本数据类型则值不能改变 -- 常量;
修饰的变量是引用类型则不能再指向其他对象,但内容可以改变
修饰的成员变量,则没有了默认赋值,需要手动赋值(显示赋值/构造代码块/构造器),如果使用构造器赋值,则要保证所有构造器都能给final成员变量赋值
final char[] chars ={'a'};//final 限定的是引用(地址) char[] chars1 = {'b'}; chars[0] = 'c'; // 修改的是值,可以 chars = chars1; // 修改的是地址,不行
抽象类Abstract
- 定义:可以定义抽象方法的普通类,除了无法创建对象,其他都可
- 普通类,普通类继承抽象类,必须实现所有的抽象方法。
- 抽象类,抽象子类继承可以自由选择实现
- abstract修饰方法时,不能有private,static,final
接口 Interface (常用)
- 接口表示一种开发标准,一种规范。表示对功能的扩展,它没有直接继承
is-a
关系,不强调属性抽象,强调行为
抽象。因此大多数接口没有全局常量的,只有方法- 接口不是类,没有构造器,没有代码块,不能继承类,支持多接口继承
- 如果一个类实现接口并继承别的类,要
先继承再实现
- 一个类可以在 继承别的类的同时
实现多个接口
- 接口有
abstract 属性
,可定义抽象方法,不能使用 final ,不能创建对象
- 一个类要先继承类,再实现接口
- 接口中的成员变量默认都是
public static final
修饰的,只能显式赋值;方法默认public abstract
- 允许接口存在实现方法
default 返回类型 方法名{}
,需要实现的就自己重写,不需要的就直接继承
内部类
成员内部类
目的:将一个类(Inner)的访问权限限定为一个类(Outer),并且使得这个类(Inner)能够访问外部类(Outer)的全部成员
类加载,先外后内
有四种访问权限修饰符
Inner 与 Outer 之间成员访问不受限;Inner 访问外部同名变量
外部类名.this
无
static
声明,全局常量final static
除外(不会触发类加载)可以通过多个内部类分别基础多个类,来间接实现
多继承
调用依赖外部类对象
// 外部静态方法,创建内部类对象 Inner in = new Outer().new Inner(); // 在外部(OtherOuter)创建内部类对象 Outer.Inner oi = new Outer().new Inner();
静态内部类
目的:借助Outer来隐藏和保护自身
只能继承
static
类与普通类功能相同,与外部类(Outer)是
平行关系
,静态内部类的类加载不会触发Outer的类加载// 在外部(OtherOuter)创建静态内部类对象 Outer.Inner oi = new OuterInner();
局部内部类
目的:继承实现外部类和接口,助Outer来隐藏和保护自身
定义在方法中/代码块中,作用域也是方法中/代码块中
- 外部类和外部其他类(非包含该内部类的类)不能访问内部类成员
功能属性与成员内部类相同,但无访问修饰符
可直接访问外部类所有成员,重名遵循就近原则
// 特殊的一些用法 public class Demo { public static void main(String[] args) { IA ia = EncloseClazz.method(); // 通过对象访问超出生命周期的局部变量,JVM会把它转为成员变量 ia.test(); } } class EncloseClazz { public static IA method() { // 默认常量,不可修改;由test()在外部调用,会被JVM添加为Inner的成员 int a = 10; class Inner implements IA { @Override public void test() { System.out.println(a); } } return new Inner(); } }
匿名内部类(取代局部内部类,常用)
- 目的:简化代码,一次性调用
- 定义在类的局部位置,作用域在定义的方法/代码块中;
- 功能与局部内部类相同
- 是类,也是一个
继承/接口子类
的对象,因此可以作为传入方法的实参
//如果继承的是一个类,()用来调用 父类构造器 赋值
new 类名/接口名(){
// 重写方法体
};
Lambda (常用)
目的:取代实现功能接口的匿名内部类
功能接口:有且仅有一个
需要实现
的抽象方法A
的接口(如由Object继承的,无需实现的抽象方法,不算),实现方法数量不限() -> {}; // () 为A的形参列表;{}为重写A的方法体 a -> {}; // 单参数可省() () -> 【方法体为一句话】; //方法体仅含有一句话,可省略{} () -> 【return的内容】; // 方法体仅含有return语句,可直接写返回内容
Lambda表达式本质是实现了接口的
子类对象
- 如果单独使用,需要使用功能接口或其父接口的
引用接收
- 也可以当做
对象
使用(形参,返回值,对象.方法)方法引用
方法返回值 与 功能接口的返回类型 兼容
方法
形参列表
与 功能接口的抽象方法A
类型 一致() -> 方法名(); // 方法用来代替{}重写的方法体 归属者::方法名;
一些特性
- Lambda表达式 没有自己的作用域,与包含自己的作用域同域
应用
回调方法:将
Lambda对象
作为一条规则传进方法public class CallBack { public static void main(String[] args) { RealCompare realCompare = new RealCompare(); // 将一个对象(Lambda)作为`参数`传递进一个方法 realCompare.comDouble(9, 4, (a, b) -> a > b ? a : b); // 求最大值 } } class RealCompare { // 接受Lambda对象的是功能接口的引用 void comDouble(double a, double b, Compare compare) { System.out.println("result = " + compare.comDouble(a, b)); } } interface Compare { double comDouble(double a, double b); }
设计模式
单例
目的:使得一个类,只能创建一个对象
实现:私有化构造方法 --> 在类内静态实例化 --> 提供获取静态实例的公有方法
// 饿汉式:加载就实例化,可能浪费资源
public class Day3MyDemo {
private int id;
private String name;
// 创建私有化静态(保证唯一性)对象实例
private static Day3MyDemo d3 = new Day3MyDemo(1, "张三");
// 私有化构造方法,防止类外new新的对象
private Day3MyDemo(int id, String name) {
this.id = id;
this.name = name;
}
// 外部获取对象的方式
public static Day3MyDemo getInstance(){
return d3;
}
}
// 懒汉式:使用时才实例化,存在线程安全问题
public class Day3MyDemo {
private int id;
private String name;
// 私有化构造方法,防止类外new新的对象
private Day3MyDemo(int id, String name) {
this.id = id;
this.name = name;
}
// 只声明,不实例化
private static Day3MyDemo day3MyDemo = null;
// 需要用时才实例化,多线程存在线程安全问题
public static Day3MyDemo getInstance(){
if (day3MyDemo == null){
day3MyDemo = new Day3MyDemo(1,"张三");
}
return day3MyDemo;
}
}