四种内部类
基本介绍
一个类的内部又完整的嵌套了另一个类结构。被嵌套的类称为内部类(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修饰)
-
局部内部类
两种内部类都遵守
说明∶ 局部内部类是定义在外部类的局部位置,比如方法中,并且有类名。
-
可以直接访问外部类的所有成员,包含私有的
-
不能添加访问修饰符,因为它的地位就是一个局部变量。局部变量是不能使用
修饰符的。但是可以使用final 修饰,因为局部变量也可以使用final
-
作用域∶仅仅在定义它的方法或代码块中。
-
局部内部类---访问-->外部类的成员 [访问方式∶ 直接访问]
-
外部类---访问-->局部内部类的成员
访问方式∶创建对象,再访问(注意∶必须在作用域内)
-
外部其他类--不能访问--->局部内部类(因为 局部内部类地位是一个局部变量)
-
如果外部类和局部内部类的成员重名时,默认遵循就近原则,如果想访问外部类的成员,则可以使用 (外部类名.this.成员)去访问【演示】
System.out,println("外部类的n2="+外部类名.this.n2);
需要解释一下原因∶!!!!Outer02.this 本质就是外部类的对象, 即哪个对象调用了 m1, Outer02.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 类或接口(参数列表){
类体
}
需求
想用IA接口,并创建对象,并且只使用一次
传统方法:
-
是写一个类,实现该接口,并且创建对象
-
如下
-
-
public class AnonymousInnerClass {
public static void main(String[] args) {
Outer04 outer04 = new Outer04();//调用
outer04.method();
}
}
class Outer04{
private int n1 = 10;
public void method(){
IA tiger = new Tiger();//多态调用Tiger
tiger.cry();
}
}
interface IA{
void cry();
}
class Tiger implements IA{//Tiger实现IA接口
-
!!!!!可以使用匿名内部类
-
简化开发
-
基于接口!!!
-
/**
* @author: XHP
* @date: 2022/4/2
* @version: 1.0
**/
public class AnonymousInnerClass {
public static void main(String[] args) {
Outer04 outer04 = new Outer04();
outer04.method();
}
}
class Outer04{
private int n1 = 10;
public void method(){
// IA tiger = new Tiger();
// tiger.cry();
//tiger的编译类型? IA
//tiger的运行类型? 就是匿名内部类 (外部类名$1)Outer04$1
/*
底层 会分配 类名Outer04$1
class tiger implements IA{
@Override
public void cry() {
System.out.println("老虎叫唤...");
}
}
底层会创建内部类Outer04$1,并且把地址赋值tiger
匿名内部类智能使用一次,之后就不能使用了
*/
IA tiger = new IA() {
-
基于类!!!
-
-
/**
* @author: XHP
* @date: 2022/4/2
* @version: 1.0
**/
public class AnonymousInnerClass {
public static void main(String[] args) {
Outer04 outer04 = new Outer04();
outer04.method();
}
}
class Outer04{
private int n1 = 10;
public void method(){
/*
编译类型Father
运行类型Outer04$1
底层会创建匿名内部类
与接口相似
class Outer04$1 extends Father{
public Outer04$1(String name) {
super(name);
}
@Override
public void test() {
System.out.println("给爷叫...");
}
}
*/
Father father = new Father("xhp"){
匿名内部类的使用
匿名内部类的语法比较奇特,因为匿名内部类既是一个类的定义,同时它本身也是一个对象,因此从语法上看,它既有定义类的特征,也有创建对象的特征,堆面前代码分析可以看出这个特点,因此可以调用匿名内部类方法。
-
有两种方式
-
方式一
-
-
方式二
-
-
/**
* @author: XHP
* @date: 2022/4/3
* @version: 1.0
**/
public class AnonymousInnerClassDetail {
public static void main(String[] args) {
Outer05 outer05 = new Outer05();
outer05.f1();
}
}
class Outer05{
private int n1 = 99;
public void f1(){
//方式一
Person p = new Person(){
最佳实战(作为参数传入)
/**
* @author: XHP
* @date: 2022/4/3
* @version: 1.0
**/
public class InnerClassExercise {
public static void main(String[] args) {
//作为参数传递
sayLoudly(new TL() {
成员内部类
!!!!!!遵守成员变量的使用,也遵守类的使用
说明:成员内部类是定义在外部类的成员位置上,并且没有static修饰
-
可以直接访问外部类的所有成员,包含私有
-
可以添加修饰符,因为他也是成员
-
作用域:和外部类一样,为整个类体
-
成员内部类---访问---->外部类(比如∶属性)【访问方式∶直接访问】(说明)
-
外部类---访问---->内部类(说明)访问方式∶ 创建对象,再访问。
-
外部其他类---访问---->成员内部类
//外部其他类---访问---->成员内部类
Outer08 outer08 = new Outer08();
Outer08.Inner08 inner08 = outer08.new Inner08();
-
演示
/**
* @author: XHP
* @date: 2022/4/3
* @version: 1.0
**/
public class MemberInnerClass {
public static void main(String[] args) {
//外部其他类---访问---->成员内部类
Outer08 outer08 = new Outer08();
Outer08.Inner08 inner08 = outer08.new Inner08();
inner08.say();
}
}
class Outer08{
private int n1 = 10;
public String name = "张三";
private void hi(){
System.out.println("hi()的方法...");
//外部类---访问---->内部类(说明)访问方式∶ 创建对象,再访问。
Inner08 inner08 = new Inner08();
System.out.println(inner08.sal);
}
//2.可以添加修饰符
public class Inner08{
private double sal = 99.8;
public void say(){
//可以直接访问外部类的所有成员,包含私有,直接访问
System.out.println("n1 = " + n1 + " name = " +name + " n1 = "+ Outer08.this.n1);
}
}
}
静态内部类
!!!!!遵守静态变量的使用规则,同时也类
使用:
-
可以直接访问外部类的所有静态成员,包含私有,但不能直接访问非静态成员
-
可以添加任意访问修饰符,他的地位是一个成员
-
作用域:同其他的成员,为一个整体
-
静态内部类---访问---->外部类(比如∶静态属性)【访问方式∶直接访问所有静态成员】
-
外部类--访问--->静态内部类 访问方式∶创建对象,再访问
-
外部其他类---访问---静态内部类
-
重名遵守就近原则
-
演示
/**
* @author: XHP
* @date: 2022/4/3
* @version: 1.0
**/
public class StaticInnerClass {
public static void main(String[] args) {
Outer10 outer10 = new Outer10();
outer10.m1();
//外部其他类---访问---静态内部类
Outer10.Inner10 inner10 = new Outer10.Inner10();
inner10.say();
}
}
class Outer10{
private int n1 = 10;
private static String name = "张三";
private static void cry(){}
public static class Inner10{
private String name = "李四";
public void say(){
//可以直接访问外部类的所有静态成员,包含私有,但不能直接访问非静态成员,直接访问
//重名遵守就近原则
System.out.println(name + Outer10.name);
cry();
}
}
public void m1(){
//外部类--访问--->静态内部类 访问方式∶创建对象,再访问
Inner10 inner10 = new Inner10();
inner10.say();
}
} -