内部类:一个类的内部又完整的嵌套了另一个类结构。别嵌套的类称为内部类(inner class),嵌套其他类的的类称为外部类(outer class)。是我们类的第五大成员(属性,方法,构造器,代码块,内部类),内部类最大的特点就是可以直接访问私有属性,并且可以体现类与类之间的包含关系。底层源码中有大量内部类。
public class InnerClass01 { //外部其他类
public static void main(String[] args) {
}
}
class Outer { //外部类
private int n1 = 100;//属性
public Outer(int n1) {//构造器
this.n1 = n1;
}
public void m1() {//方法
System.out.println("m1()");
}
{//代码块
System.out.println("代码块...");
}
class Inner { //内部类, 在Outer类的内部
}
}
内部类的分类:
一,定义在外部类局部位置上:
①,局部内部类(有类名);
②,匿名内部类(无类名,重点);
二,定义在外部类的成员位置上:
①,成员内部类(无static修饰);
②,静态内部类(有static修饰);
局部内部类:
局部内部类是定义在外部类的局部位置的,如方法中,并且有类名。
1,可以直接访问外部类的所有成员,包括私有的。
2,不能添加访问修饰符,因为它的地位就是一个局部变量。局部变量是不能使用修饰符的。但是可以使用final修饰,因为局部变量可以使用final。
3,作用域:仅仅在定义它的方法或代码块中。
4,局部内部类访问外部类的成员的访问方式是直接访问。
5,外部类访问局部内部类的成员的访问方式是创建内部类的对象,通过对象访问。(必须在作用域中)
6,外部其他类不能访问局部内部类,因为局部内部类地位是一个局部变量。
7,如果外部类和局部内部类的成员重名是,默认遵循就近原则,如果想访问外部类的成员,可以使用 外部类名.this.成员 的方式去访问。
注意:局部内部类定义在方法或代码块中。作用域在方法体或代码块中,其本质还是一个类
/**
* 演示局部内部类的使用
*/
public class LocalInnerClass {//
public static void main(String[] args) {
//演示一遍
Outer02 outer02 = new Outer02();
outer02.m1();
System.out.println("outer02的hashcode=" + outer02);
}
}
class Outer02 {//外部类
private int n1 = 100;
private void m2() {
System.out.println("Outer02 m2()");
}//私有方法
public void m1() {//方法
//1.局部内部类是定义在外部类的局部位置,通常在方法
//3.不能添加访问修饰符,但是可以使用final 修饰
//4.作用域 : 仅仅在定义它的方法或代码块中
final class Inner02 {//局部内部类(本质仍然是一个类)
//2.可以直接访问外部类的所有成员,包含私有的
private int n1 = 800;
public void f1() {
//5. 局部内部类可以直接访问外部类的成员,比如下面 外部类n1 和 m2()
//7. 如果外部类和局部内部类的成员重名时,默认遵循就近原则,如果想访问外部类的成员,
// 使用 外部类名.this.成员)去访问
// 老韩解读 Outer02.this 本质就是外部类的对象, 即哪个对象调用了m1, Outer02.this就是哪个对象
System.out.println("n1=" + n1 + " 外部类的n1=" + Outer02.this.n1);
System.out.println("Outer02.this hashcode=" + Outer02.this);
m2();
}
}
//6. 外部类在方法中,可以创建Inner02对象,然后调用方法即可
Inner02 inner02 = new Inner02();
inner02.f1();
}
}
匿名内部类:
匿名内部类是定义在外部类的局部位置,并且没有类名;
基本语法:
new 类 或 接口(参数列表){ 类体 }
注意:
①,本质上还是类;②,该类没有名字(但是在jdk底层系统会自动分配名字);④即使内部类,同时还是个对象
/**
* 演示匿名内部类的使用
*/
public class AnonymousInnerClass {
public static void main(String[] args) {
Outer04 outer04 = new Outer04();
outer04.method();
}
}
class Outer04 { //外部类
private int n1 = 10;//属性
public void method() {//方法
//基于接口的匿名内部类
//老韩解读
//1.需求: 想使用IA接口,并创建对象
//2.传统方式,是写一个类,实现该接口,并创建对象
//3.老韩需求是 Tiger/Dog 类只是使用一次,后面再不使用
//4. 可以使用匿名内部类来简化开发
//5. tiger的编译类型 ? IA
//6. tiger的运行类型 ? 就是匿名内部类 Outer04$1
/*
我们看底层 会分配 类名 Outer04$1
class Outer04$1 implements IA {
@Override
public void cry() {
System.out.println("老虎叫唤...");
}
}
*/
//7. jdk底层在创建匿名内部类 Outer04$1,立即马上就创建了 Outer04$1实例,并且把地址
// 返回给 tiger
//8. 匿名内部类使用一次,就不能再使用
IA tiger = new IA() {
@Override
public void cry() {
System.out.println("老虎叫唤...");
}
};
System.out.println("tiger的运行类型=" + tiger.getClass());
tiger.cry();
tiger.cry();
tiger.cry();
// IA tiger = new Tiger();
// tiger.cry();
//演示基于类的匿名内部类
//分析
//1. father编译类型 Father
//2. father运行类型 Outer04$2
//3. 底层会创建匿名内部类
/*
class Outer04$2 extends Father{
@Override
public void test() {
System.out.println("匿名内部类重写了test方法");
}
}
*/
//4. 同时也直接返回了 匿名内部类 Outer04$2的对象
//5. 注意("jack") 参数列表会传递给 构造器
Father father = new Father("jack"){
@Override
public void test() {
System.out.println("匿名内部类重写了test方法");
}
};
System.out.println("father对象的运行类型=" + father.getClass());//Outer04$2
father.test();
//基于抽象类的匿名内部类
Animal animal = new Animal(){
@Override
void eat() {
System.out.println("小狗吃骨头...");
}
};
animal.eat();
}
}
interface IA {//接口
public void cry();
}
//class Tiger implements IA {
//
// @Override
// public void cry() {
// System.out.println("老虎叫唤...");
// }
//}
//class Dog implements IA{
// @Override
// public void cry() {
// System.out.println("小狗汪汪...");
// }
//}
class Father {//类
public Father(String name) {//构造器
System.out.println("接收到name=" + name);
}
public void test() {//方法
}
}
abstract class Animal { //抽象类
abstract void eat();
}
②,匿名内部类的语法比较奇特,因为匿名内部类既是一个类的定义,同时它本身也是一个对象,因此,从语法上看,他既有定义类的特征,因此可以直接调用匿名内部类的方法。
③,可以直接访问外部类的所有成员,包含私有的。
④,不能添加访问修饰符,因为它的地位就是一个局部变量。
⑤,作用域:仅仅在定义它的方法或代码块中。
⑥,匿名内部类访问外部类的成员的访问方式是直接访问。
⑦,外部其他类不能访问匿名内部类,因为匿名内部类地位是一个局部变量。
⑧,如果外部类和匿名内部类的成员重名是,默认遵循就近原则,如果想访问外部类的成员,可以使用 外部类名.this.成员 的方式去访问。
public class AnonymousInnerClassDetail {
public static void main(String[] args) {
Outer05 outer05 = new Outer05();
outer05.f1();
//外部其他类---不能访问----->匿名内部类
System.out.println("main outer05 hashcode=" + outer05);
}
}
class Outer05 {
private int n1 = 99;
public void f1() {
//创建一个基于类的匿名内部类
//不能添加访问修饰符,因为它的地位就是一个局部变量
//作用域 : 仅仅在定义它的方法或代码块中
Person p = new Person(){
private int n1 = 88;
@Override
public void hi() {
//可以直接访问外部类的所有成员,包含私有的
//如果外部类和匿名内部类的成员重名时,匿名内部类访问的话,
//默认遵循就近原则,如果想访问外部类的成员,则可以使用 (外部类名.this.成员)去访问
System.out.println("匿名内部类重写了 hi方法 n1=" + n1 +
" 外部内的n1=" + Outer05.this.n1 );
//Outer05.this 就是调用 f1的 对象
System.out.println("Outer05.this hashcode=" + Outer05.this);
}
};
p.hi();//动态绑定, 运行类型是 Outer05$1
//也可以直接调用, 匿名内部类本身也是返回对象
// class 匿名内部类 extends Person {}
// new Person(){
// @Override
// public void hi() {
// System.out.println("匿名内部类重写了 hi方法,哈哈...");
// }
// @Override
// public void ok(String str) {
// super.ok(str);
// }
// }.ok("jack");
}
}
class Person {//类
public void hi() {
System.out.println("Person hi()");
}
public void ok(String str) {
System.out.println("Person ok() " + str);
}
}
//抽象类/接口...
以上内容为个人学习笔记,代码内容来源于B站up韩顺平。