0.基础信息
1.权限
详细信息
四大权限
默认都可以访问本类
- public(公共访问权限):最高权限,任何类都可以使用
- private(本类访问权限):最低权限,只有本类可以使用
- protected(子类访问权限):同包类和子类
- default(包访问权限):只有同包类可以访问
权限 | ||
---|---|---|
类 | public | |
方法 | public private protected | |
局部变量 | 不可使用,跟方法权限相同 | |
成员变量 | public private protected 默认 |
2.重置
1.重写
- 规则(两同两小一大):
- 两同:派生类的方法名/参数列表与超类完全相同
- 两小:派生类的返回值/异常小于或等于超类
- 一大:派生类的访问权限大于或等于超类
2.重载
- 规则
- 参数名相同
- 参数列表不允许重复
3.造型
1.向上造型
向上造型时父类对象只能使用父类的方法,如果子类重写方法则使用的就是子类方法,不能再使用子类的方法;
原本的子类对象变为父类对象提高了兼容性和可操作性;
1 | B extends A(); |
重写是虚拟机运行期执行, 根据对象的不同而不是引用类型的不同,去调用不同的版本。
2.向下造型
类似于强制类型转换,用于将向上造型的父类强制转换为子类,只能转换为对应的子类否则会报错
1 | B b = (B)a; |
4.比较
比较符号 | 特点 |
---|---|
== | 判断两侧的引用在栈中对应的内容是否相同 |
equals | |
instanceof | 1.左侧引用类型obj ,右侧类名class 2.判断obj是否是class类型的之间或间接子类 |
1.==
2.equals
比较公式:
1
obj1.equals(obj2);
注意事项:
- 在object中默认equals方法,单纯的
==
,可以重写,多数类中已经重写过了,实际环境中创建实体类时可以重写(可以使用编辑工具自行生成); - obj1是null的话会引发空指针异常,因此在实际环境中,比较把已知不为空的写在左侧.
- 在object中默认equals方法,单纯的
源码:
Object原始方法
1
2
3public boolean equals(Object obj) {
return (this == obj);
}重写
1
3.instanceof
比较公式:
1
obj instanceof Class
注意事项:
- obj必须为引用类型,不能是基本类型;
- obj为null,则返回false;
- Obj obj=new class(),则返回true;
- class是obj的直接或间接父类,返回true;
obj是数组时,只有object返回true;
1.修饰符
1.final
修饰对象 | 作用 | 注意事项 |
---|---|---|
类 | 不能被继承 | |
方法 | 不能被重写 | |
引用 | 引用 :不能被修改(不能指向别的对象);指向的对象 :可以被修改 |
适用情况:方法的参数/实例化 |
变量 | 不能被重新赋值 | 局部变量:在使用之前被初始化赋值就行; 成员变量:必须直接初始化; |
1 | //局部变量赋值的两种方法 |
2.static
- 静态内容可以被多个对象所共享,因此一个对象修改后其他对象再次引用的是修改后的内容;
- 静态内容不能直接访问非静态内容(因为类加载的时候就会先加载静态内容,再加载实例,因此执行顺序也高);
- 静态内容就不再属于对象而是属于类,所以存储在方法区;
- 静态方法调用可以类名点,也可以引用点(但是不推荐);
- 静态方法不能使用this:因为this代表当前对象,而静态方法属于类,因此不能使用;
3.abstract
抽象方法:
抽象方法必须被重写;
如果继承抽象类的是普通类,那么抽象方法必须被重写.如果继承抽象类也是抽象类那么抽象方法可以只继承不重写;抽象方法没有方法体(没有{});
抽象类:
- 不能实例化,只有被继承才能有意义;
- 抽象类内的构造器,主要继承给子类创建实例时使用.抽象类的普通方法主要是继承给子类使用的();
- 含有抽象方法的类一定是抽象类.但是抽象类中可以不含有抽象方法;
注意事项:
abstract不能和final和static一起使用;
final修饰的类不能被继承,修饰的方法不能被重写,而abstract修饰的类必须要被继承,修饰的方法必须被重写static修饰的方法就不再属于类,用类名就可以调用,但是如果使用abstract修饰的方法,用父类直接调用就会导致调用一个没有方法体的方法;
abstract不能修饰变量和构造器;
abstract不能定义为private访问权限;
2.修饰符相关
1.变量
1.定义变量
直接赋值
1
int a =1;
先声明再赋值
1
2int a;
a=20;
2.命名规则
- 只能包含
字母
、数字
、_
、$
,不能用数字开头; - 区分大小写;
- 不能使用关键字;
- 建议使用英文/见名知意/驼峰命名法
3.分类
根据位置不同
分类 分类依据 内存 成员变量 类中的变量 成员变量在对象中,对象被回收,成员变量失效; 局部变量 方法中的变量 局部变量在方法中,方法执行完毕,局部变量失效; 根据修饰符
分类 分类依据 内存 实例变量 没有被static修饰 实例变量属于对象,保存在堆中,有几个对象就保存几份 静态变量 被static修饰 静态变量属于类,保存在方法区中的静态区,只保存一份
4.优先级
局部变量>>>成员变量
2.常量
1.定义常量
被final static同时修饰的成员变量(不能定义在方法内)
1 | final static int A_A =1; |
2.命名规则
类似变量的明明规则,但是全部使用大写,单词之间用_
连接
3.接口
1.基础信息
[]
部分可以省略不写,编译器自动补全;
属性 | 修饰符 | JDK | 注意事项 |
---|---|---|---|
接口 | public [abstract] interface | 1.7 | 1.一个类可以实现多个接口; 2.一个接口可以继承多个接口,抽象方法可以重复; |
常量 | [public static final] | 1.7 | 1.接口中没有成员变量只有常量; 2.只能通过接口名调用或者被默认方法引用 |
抽象方法 | [public abstract] | 1.7 | 必须被重写 |
默认方法 | [public] default | 1.8 | 1.实现功能的方法,类似抽象方法中普通方法; 2.可以引用接口中所有类型的方法; 3.可以被重写,修饰符变为 public ;4.实现后不会出现空方法,接口增加方法不用修改所有实现类; |
静态方法 | [public] static | 1.8 | 1.不能通过对象进行调用,只能通过接口名调用 2.只能通过接口名调用或者被默认方法引用 3.可以被重写; |
私有方法 | private | 1.9 | 默认方法的私有方法 |
静态私有方法 | private static | 1.9 | 静态方法的私有方法 |
2.函数式接口
函数式接口
只包含一个抽象方法的接口,java8专门为函数式接口提供了@FunctionalInterface
注解
3.内部类
- 外部类不能直接访问内部类,内部类成员可以访问外部类的私有数据;
- 外部类不可以使用”private/protected/static”修饰符
1.成员内部类
区别
名称 区别 注意事项 静态内部类 使用static修饰的成员内部类 不能有静态方法/静态成员变量/静态初始化块 非静态内部类 不使用static修饰的成员内部类 static关键字的作用
- 外部类的外一层是包不能用static修饰;内部类的外一层是外部类能用static修饰;
- 把内部类变成外部类的类相关,而不是外部类的实例(对象)相关;
查找变量顺序
内部类局部变量>>>内部类成员变量>>>外部类成员变量
保存文件形式
外部类:外部类名.class
内部类:外部类名&内部类名.class
1.非静态内部类
外部类访问内部类:
在外部类方法内新建内部类访问内部类,main方法不能新建非静态内部类对象(编译错误)
1
2
3
4
5
6
7class out{
class Int{
}
public static void main(String[] args){
Int int = new out.new Int();
}
}可以访问内部类方法,但是不能访问内部类变量(编译出错);
内部类访问外部类:都行
2.静态内部类
外部类访问内部类:
在外部类方法内或main内都能新建对象或者直接内部类名调用;
1
2
3
4
5
6
7class out{
static class Int{
}
public static void main(String[] args){
Int int = new out.new Int();
}
}可以访问内部类变量,但是不能访问内部类方法(编译出错);
内部类访问外部类:
静态内部类不能访问外部类的实例成员,只能访问外部类的类成员;
静态内部类对象只持有外部类的类引用,没有持有外部类的对象引用静态内部类可以包含静态成员,也可以包含非静态成员;
- 接口内部类[了解即可]
- 只能使用public static修饰接口内部类;
- 接口的作用是定义一个公共规范(暴露出来供大家使用),如果把这个接口定义成一个内部接口就没有意义了;
2.局部内部类
3.匿名内部类
要求:
- 必须且只能实现或继承一个类;
- 继承只是单纯的新建类+重写需要用到的内容;
- 匿名内部类不能是抽象类(没有意义),不能定义构造器(没有类名);
- 匿名内部类是:需要创建并使用一次的类;
书写格式
继承:
1
2
3new 父类([参数]){
重写
}实现:
1
2
3new 实现类(){
重写
}
匿名内部类使用外部类成员内部类时,成员内部类必须要被
final
修饰,java1.8以后自动在编译时在成员变量前添加final案例:
父类
1
2
3
4
5
6
7
8
9
10
11public class Father {
public Father(String name) {
super();
Name = name;
}
省略:有参无参构造器
private String Name;
private Integer age;
private String Book;
省略:get/set方法
}外部类:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16public class Test{
public void father() {
//java1.8后自动在成员变量前加上final,再次复制则编译错误
String book="数学";
//book="12";
Father father = new Father("刘备") {
public Integer getAge() {
return 10;
}
public String getBook() {
return book;
}
};
System.out.println("姓名:"+father.getName()+",年龄:"+father.getAge()+",书籍:"+father.getBook());
}
}
4.Lambda表达式
作用:
- 在java8以后允许将代码作为参数传入方法中;
- 允许用更简洁的代码来创建函数式接口;
- 匿名内部方法,所以只有一个方法
表达式
1
2
3
4(Integer a1,Integer a2,...)->{
代码块;
return x;
}简写
只有一行代码时,可以省略
{}
1
(Integer a1,Integer a2,...)->代码1;
只有一个参数时,可以省略
()
1
Integer a1->{代码1;代码2};
没有参数时,必须书写
()
1
()->Integer a1->{代码1;代码2};
代码块只有一行代码,代码值就是表达式返回值
1
Integer a1->X x = new x;
极简
1
()-->代码;
X
- 将Lambda表达式赋值给函数式接口类型的变量.
- 将Lambda表达式作为函数式接口类型的参数传给某个方法.
- 使用函数式接口对Lambda表达式进行强制类型转换.
- Lamdba表达式实现的匿名方法与目标类型中惟一的抽象方法有相同的参数列表
- Lamdba表达式也可以强制转换为带参数的表达式
4.内存
存储内容
存储 内容 栈 引用(堆内存地址)、栈帧(方法(局部变量+参数))、基本数据类型 堆 对象/实例变量 方法区 类文件的字节码信息/静态内容(静态区)
1. 栈帧
每调用一个方法,jvm就会在栈中为方法创建一个栈帧用于存储:方法(局部变量+参数),方法执行完后栈帧消失
2.内存
内存泄露:
不再使用的内存(栈或堆)还没有被及时的的回收
垃圾回收:
- 垃圾回收期(CG)不定时到内存堆中清扫垃圾(没有任何引用所指向的对象)。
- 并不一定发现垃圾就立刻回收
- 不能控制垃圾的回收只能通过调用System.gc()建议JVM尽快调度GC来回收
3.方法区
在产生栈堆关系之前,会通过类加载器载入类文件的字节码信息,经过解析后类的信息装入方法区.类的信息包括
成员变量
/方法定义
/静态内容,并只保留一份;内容
1
2
3
4
5
6类名.class{
成员变量1;成员变量2;
方法名(){
}
静态方法
}
4.事例
实例1
1
2
3
4
5
6
7
8public static void main(String[] args) {
Double price= 12.5;
test1("数学", price);//调用完test1方法之后,此栈帧消失
System.out.println(price);
}
public static void test(String aname,Double price) {
price = price+10;
}此时card为同一对象
1
2
3
4
5
6
7
8
9public static void main(String[] args) {
Integer age = 20;
Father father = new Father(age);
test2("代维",father);
System.out.println(father.age);
}
public static void test(String name,Father father) {
father.age+=20;
}
5.GC回收
解决方法:
建议GC回收上
1
System.gc();
查看内存占用情况
获取Runtime对象
1
Runtime runtime = Runtime.getRuntime();
获取jvm所占最大内存
1
runtime.maxMemory()/1024/1024+"M"
当前jvm所占最大内存
1
runtime.totalMemory()/1024/1024+"M"
剩余内存
1
runtime.freeMemory()/1024/1024+"M"
最后更新: 2019年11月06日 11:36