Java
大约 6 分钟
Java
目录
内部类(这章不看书了,看视频学)
简概
概念
概念
- 什么是内部类?内部类就是在类里面再定义一个类
使用场景
- 内部类表示的事物是外部类的一部分
- 内部类单独出现没有任何意义
访问权限
- 内部类可以访问外部类包括私有在内的所有成员
- 外部类要访问内部类成员时必须创建对象
使用场景举例
例如:汽车的发动机、ArrayList的迭代器、人的心脏
汽车的发动机
/* * - 需求:写一个Javabean类描述汽车 * - 属性:品牌、车龄、颜色、发动机品牌、使用年限 */ public class Car { String carName; int carAge; int carColor; public class Engine { // 需要依赖车,不会单独定义 String engineName; int engineAge; } }
核心类库ArrayList
IDEA > Ctrl+N > 输入ArrayList > 选择ArrayList.java.util
文件中Ctrl+F10 > 会出现很多类内内容,红色m是方法、黄色f是字段/属性、蓝色C是内部类
然后可以看到里面有四个内部类,现在我们看内部类
Itr
。
归纳总结一下
类的五大成员:属性、方法、构造方法、代码块、内部类
类的相对位置可分:外部类、内部类、外部其他类
内部类的分类:
- 成员内部类(不需要自己写,能看懂就行)
- 静态内部类(不需要自己写,能看懂就行)
- 局部内部类(不需要自己写,能看懂就行)
- 匿名内部类**(实际开发用得最多)**
成员内部类
简概
- 概念
- 写在成员位置的,属于外部类的成员
- 注意
- 成员内部类可以被一些修饰符所修饰,比如:private、默认、protected、public、static等
- 我们一般说 “成员内部类” ,不指用static修饰的情况,那叫 “静态内部类”
- JDK16之前不能在成员内部类里面定义静态变量
定义内部类
public class Car { // 外部类
string carName;
int carAge;
int carcolor;
class Engine { // 成员内部类
string engineName;
int engineAge;
}
}
外界调取
方式一:在外部类中编写方法,对外提供内部类的对象
方式二:直接创建格式:
外部类名.内部类名 对象名 = 外部类对象.内部类对象
public class Outer { String name; /*private*/ class Inner { static int a = 10; // 注意:JDK16之前不能在成员内部类里面定义静态变量 } public Inner getInstance(){ return new Inner(); } } // 创建内部类的方式 2 System.out.println(new Outer().name); // 获取普通成员 Outer.Inner oi = new Outer().new Inner(); // 获取内部类。如果内部类是private则不能用该写法 // 创建内部类的方式 1 Outer o = new Outer(); Object inner = o.getInstance(); System.out.println(o.getInstance()); // 或
例如核心内库中的ArrayList
public Interator<E> iterator() { // 该方法返回ArrayList类里的迭代器(内部类) return new Itr(); } private class Itr implement Interator<E> {...}
成员内部类获取外部类、原理
public class Outer {
private int a = 10;
class Inner {
private int a = 20;
public void show() {
int a = 30;
system.out.println(a); // 30
system.out.print1n(this.a); // 20
system.out.print1n(Outer.this.a); // 10
}
}
}
原理(内存图)
静态内部类
简概
静态内部类只能访问外部类中的静态变量和静态方法,如果想要访问非静态的需要创建对象。
定义内部类
public class Car{ // 外部类
String carName;
int carAge;
int carColor;
static class Engine{ // 静态内部类
String engineName;
int engineAge;
}
}
// 创建静态内部类
外部类名.内部类名 对象名 = new 外部类名.内部类名();
// 调用非静态方法的格式
先创建对象再用对象调用
// 调用静态方法的格式
外部类名.内部类名.方法名();
外界调取
注意事项
静态内部类也是成员内部类中的一种
静态内部类只能访问外部类的静态变量和静态方法,如果想要访问非静态的需要创建外部类的对象
先复习一下 静态成员变量
public class Outer {
int a = 10; // 非静态成员变量
static int b = 20; // 静态成员变量
// 静态内部类
static class Inner {
public void show1(){ // 非静态方法
Outer o = new Outer();
system.out.print1n(o.a); // 非静态成员变量
system.out.print1n(b); // 静态成员变量
}
public static void show2(){ // 静态方法
Outer o = new Outer();
system.out.print1n(a) ; // 非静态成员变量
system.out.println(b); // 静态成员变量
}
}
}
调用 静态内部类
public class Outer {
// 静态内部类
static class Inner {
public void show1(){
System.out.println("静态内部类里的 非静态方法")
}
public static void show2(){
System.out.println("静态内部类里的 静态方法")
}
}
}
public class Test{
public static void main(String[] args) {
Outer.Inner oi = new Outer.Inner(); // 静态内部类
oi.show1(); // 静态内部类里的 非静态方法
// oi.show2(); // (强行写也行)
Outer.Inner.show2(); // 静态内部类里的 静态方法
}
}
局部内部类
简概
概念:将内部类定义在方法里面就叫做局部内部类,类似于方法里面的局部变量。
没什么用
定义内部类
public class Outer{
public void show(){
int a = 10;
// 局部内部类。和局部变量是类似的,可以使用一些final static等的修饰符
class Inner{
}
}
}
外界调取
该局部内部类只能在局部里使用,外界用不了
访问权限
- 外界是无法直接使用,需要在方法内部创建对象并使用。
- 该类可以直接访问外部类的成员,也可以访问方法内的局部变量。
匿名内部类【重要】
简概
概念
- 匿名内部类的本质是隐藏了名字的内部类
结构 匿名内部类包含三部分,更准确得说应该叫 “匿名内部类的对象”
继承或实现
方法重写
创建对象
补充 可以些在成员位置,也可以写在局部位置。
定义内部类
格式
// 格式
new 类名或接口名() {
重写方法;
}
// 例如
new Inter() {
public void show() {
}
}
代码与原理
public class Test {
public static void main(String[] args){
// 编写匿名内部类的代码
new Swim() {
@Override
public void swim(){
System.out.println("重写的游泳方法")
}
}
}
}
// 分析
// 1. 下面的Student类实现Swim接口了
// 2. 大括号前面的内容删掉,换成Swim,便成了一个匿名内部类
// 3. Swim的前面加关键字new、后面加括号,表示创建这个类的对象
public class Student implements Swim { // 你会发现大括号里的内容和匿名内部类是一样的
@Override
public void swim(){
System.out.println("重写的游泳方法")
}
}
应用举例、原理、应用场景
public class Test {
public static void main( String[] args) {
// 编写匿名内部类的代码
// 编译时其实会生成相关字节码:Test$1.class(可以在工程文件的out文件里找),这个名字是自动生成的。
// 可以用javap反编译这个字节码,会发现这个文件的内容就是这个匿名类的内容
new swim(){
@override
public void swim(){ system.out.println("重写了swim方法"); }
};
// 应用场景:如果这个类只要用一次,就可以不去重新定义一个类,简化代码
// 然后比如这个类就可以传给接受Animal引用的函数
new Animal(){
@override
public void eat() { system.out.println("重写了eat方法"); }
};
}
}