一:基本介绍
一个类的内部又完整的嵌套了另一个类结构,被嵌套的类成为内部类
嵌套其他类的类称为外部类( outer class )。是类的第五大成员。
:::danger
类的五大成员!!!!!
属性,方法,构造器,代码块,内部类
:::
内部类的最大特点是可以直接访问私有属性,迫切可以直接提现类与类之间的包含关系
在看底层源码时,有大量的内部类
1:内部类的分类
- 定义在外部类局部位置上
- 局部内部类
- 匿名内部类
- 定义在外部类的成员位置上
- 可以直接访问外部类的所有成员,包含私有的
- 不能添加访问修饰符,但是可以使用final修饰,因为局部变量也可以使用final
- 作用域:仅仅在定义他的方法或者代码中
- 局部内部类可以直接访问外部类的成员
- 外部类 —> 访问 —> 局部内部类的成员
- 访问方式:创建对象,再访问,(注意必须在作用域中)作用域:定义的方法或者代码块中。
外部其他类不能访问局部内部类(因为局部内部类是一个局部变量) ```java public class InnerCLass { public static void main(String[] args) {
Outer outer = new Outer();
outer.Sakura();
//执行sakura()方法时,在方法体内定义局部内部类
//定义完之后再执行下面的创建对象
}
} class Outer { //外部类 private int n1 = 10; //属性
private void Test(){ //私有方法
System.out.println("Test方法");
}
public void Sakura(){ //方法
//可以用final修饰
final class Inner{ //局部内部类
private int n1 = 100;
public void F(){
//局部内部类:访问--> 外部类的成员
//[ 访问方式:直接访问 ]
System.out.println(n1);
Test();
//如果有重名的,就近原则
//若想访问外部类的成员使用:外部类名.this.成员
//因为外部类名.成员 只有在静态的时候才这样
//非静态,非共有。需要加this表明是这个对象的属性
System.out.println("内部类的成员"+ n1);
System.out.println("外部类的的n1" + Outer.this.n1);
}
}
//外部类在局部内部类作用域(定义局部内部类-的方法体或者代码块)
//中,可以创建对象,然后调用方法即可
Inner inner = new Inner();
inner.F();
}
}
<a name="Bxmuj"></a>
### 五:匿名内部类
<a name="kbDUw"></a>
#### 1:基本使用
1. 本质是类
2. 内部类
3. 该类没有名字
4. 同时还是一个对象
:::danger
说明:匿名内部类是定义在外部类的局部位置,比如方法中并且没有类名
:::
```java
public class AnonymousInnerClass {
public static void main(String[] args) {
outer outer = new outer();
outer.method();
}
}
class outer{
private int n1 = 10;
public void method(){
//需求:使用A接口,并创建对象
//传统写法:创建类实现接口,创建对象调用方法
// A cat = new cat();
//cat.cry();
//需求:类只使用一次,后面不在使用
//使用匿名内部类
//编译类型:A 运行类型:匿名内部类 Onter&1
//底层
/*
class Outer04$1 implements IA {
@Override public void cry() {
System.out.println("猫叫了");
}
}
*/
//jdk 底层在创建匿名内部类 Outer04$1,立即马上就创建了 Outer04$1 实例
//并且把地址返回给 tiger
A cat = new A(){
@Override
public void cry() {
System.out.println("猫叫了");
}
};
//通过getclass来查看当前的运行类型
System.out.println("Cat的运行类型:"+ cat.getClass());
cat.cry();
}
}
interface A{
public void cry();
}
/*class cat implements A{
@Override
public void cry() {
System.out.println("猫叫了");
}
}*/
class father{
public father(String name) {
System.out.println("接收到name"+ name);
}
}
2:匿名内部类的细节
匿名内部类即时一个类的定义,同时也是一个对象,因此从语法上看,它既有定义类的特征,也有创建对象的特征。
public class TestClass {
public static void main(String[] args) {
Test T = new Test();
T.A();
}
}
class Test{
//创建一个基于类的匿名对象
public void A(){
//第一种匿名内部类创建方法
Person person = new Person(){
@Override
public void speak() {
System.out.println("重写Person里的speak方法");
}
};
person.speak(); //动态绑定 运行类型是Test&1
//第二种匿名内部类创建方法
//底层 class 匿名内部类 extends Person
new Person(){
@Override
public void speak() {
System.out.println("重写Person里的speak方法");
}
@Override
public void eat(String name) {
// super.eat(name); 调用父类也就是Person的eat方法
System.out.println(name+"吃饭了");
}
}.eat("sakura");
}
}
class Person{
public void speak(){
System.out.println("人说话");
}
public void eat(String name){
System.out.println("人吃饭");
}
}
:::danger 其他和局部内布类一样:
可以直接访问外部类的所有成员,包含私有的
- 不能添加访问修饰符,因为它的地位就是一个局部变量
- 作用域:仅仅在定义它的方法或代码块
- 匿名内部类—-访问——>外部类成员
- 外部其他类—- 不能访问——->匿名内部类(因为匿名内部类地位是一个局部变量)
如果外部类和匿名内部类的成员重名时,匿名内部类访问的话,默认遵循就近原则,如果想访问外部类的成员,则可以使用(外部类名.this.成员)去访问 :::
六:匿名内部类的最佳实践
1:当做实惨传递
```java public class Test00 { public static void main(String[] args) {
//当做实惨直接传递,简洁高效
Test(new AA() {
@Override
public void eat() {
System.out.println("人吃饭");
}
});
//传统方法
Test(new Person());
}
public static void Test(AA aa){
aa.eat();
} }
interface AA{ public void eat(); }
//传统方法 class Person implements AA{ @Override public void eat() { System.out.println(“吃饭吃饭吃饭”); } }
<a name="Inq7H"></a>
##### 2:
![image.png](https://cdn.nlark.com/yuque/0/2022/png/2595924/1660632068047-a99a4e4b-623b-4027-9081-76956a4e9cb5.png#clientId=u7e033b8d-da80-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=268&id=u644d0e86&margin=%5Bobject%20Object%5D&name=image.png&originHeight=268&originWidth=594&originalType=binary&ratio=1&rotation=0&showTitle=false&size=241819&status=done&style=none&taskId=u4592abb6-d889-418f-bba1-83dfeb76050&title=&width=594)
```java
public class Test01 {
public static void main(String[] args) {
Cellphone cellphone = new Cellphone();
//1. 传递的是实现了 Bell 接口的匿名内部类 InnerClassExercise02$1
// 2. 重写了 ring
//Bell bell = nee Bell(){
// @Override
// public void Ring() {
// System.out.println("起床了");
// }
//}
cellphone.alarmClock(new Bell() {
@Override
public void Ring() {
System.out.println("起床了");
}
});
cellphone.alarmClock(new Bell() {
@Override
public void Ring() {
System.out.println("不起床");
}
});
}
}
interface Bell {
public void Ring();
}
class Cellphone{
public void alarmClock(Bell bell){
bell.Ring();
}
}
七:成员内部类的使用
:::danger 说明:成员内部类定义在外部类的的成员位置,并且没有static修饰 :::
- 可以直接访问外部类的所有成员,包含私有的属性
- 可以添加任意访问修饰符
- 作用域
- 和外部类的其他成员一样,为整个类体。
- 成员内部类访问外部类对象(比如:属性)
- 访问方式:直接访问
- 外部类访问成员内部类
- 访问方式:创建对象,再访问
外部其他类访问 ```java public class Test02 { public static void main(String[] args) {
Outer outer = new Outer();
outer.UseInnerClass();
//外部其他类访问成员内部类的三种方式
//(前提要先创建外部类)
//第一种
outer.new Inner();//new Inner()当做是 outer 成员
Outer.Inner inner = outer.new Inner();
//第二种 在外部类中编写一个方法,可以返回Inner对象
//接收通过InnerInstance返回的Inner对象
Outer.Inner innerInstance = outer.getInnerInstance();
} }
class Outer{ //外部类 private int Num = 10; private void Test(){ System.out.println(“外部类的Test方法”); } public class Inner{ //成员内部类 //可以直接访问外部类的所有静态成员,包含私有的,但不能直接访问非静态成员 private int Num = 100; public void Say(){ System.out.println(“外部类的Num:”+ Outer.this.Num); System.out.println(“成员内部类Num:” + Num); } } //使用成员内部类 //通过写方法,创建成员内部类的对象,然后使用相关的方法 public void UseInnerClass(){ Inner inner = new Inner(); inner.Say(); } public Inner getInnerInstance(){ //返回一个Inner实例,但是没有对象接收 return new Inner(); } }
<a name="SLwM1"></a>
### 七:静态内部类的使用
:::danger
**_说明:静态内部类是定义在外部类的成员位置,并且有static修饰_**
:::
1. **_可以直接访问外部类的所有静态成员,包含私有的,但不能直接访问非静态成员_**
2. **_可以添加任意访问修饰符(pubic,protected,默认,private)因为它的地位就是一个成员_**
3. **_作用域:_**
1. **_同其他的成员一样,为整个类体_**
4. **_静态内部类访问外部类(比如:静态属性)_**
1. **_访问方式:直接访问所有静态成员_**
5. **_外部类访问静态内部类_**
6. **_外部其他类范文静态内部类_**
7. **_如果外部类和静态内部类的成员,泽可以使用(外部类。成员)去访问_**
```java
public class Tets00 {
public static void main(String[] args) {
Outer outer = new Outer();
outer.UseInnerClass();
//第一种:
//因为静态内部类,是可以通过类名直接访问(前提是满足访问权限)
Outer.Inner inner = new Outer.Inner();
//第二种
//编写一个方法,可以返回静态内部类的对象实例.
Outer.Inner inner1 = outer.getInner();
}
}
class Outer{ //外部类
private static int Num = 10;
private void Test(){
System.out.println("外部类的Test方法");
}
public static class Inner{ //成员内部类
//可以直接访问外部类的所有静态成员,包含私有的,但不能直接访问非静态成员
private int Num = 100;
public void Say(){
System.out.println("外部类的Num:"+ Outer.Num);
System.out.println("成员内部类Num:" + Num);
}
}
//外部类访问静态内部类
//通过写方法,创建成员内部类的对象,然后使用相关的方法
public void UseInnerClass(){
Inner inner = new Inner();
inner.Say();
}
public Inner getInner(){
//返回一个Inner实例,但是没有对象接收
return new Inner();
}
}
:::danger
非静态成员内部类创建对象
new Inner( )当做是 outer 成员
Outer.Inner inner1 = outer.new Inner( );
静态成员内部类创建对象
因为静态内部类,是可以通过类名直接访问(前提是满足访问权限)
Outer.Inner inner2 = new Outer.Inner( );
:::
七:练习
public class Test {//外部类
public Test() {//构造器
Inner s1 = new Inner();
s1.a = 10;
Inner s2 = new Inner();
System.out.println(s2.a);
}
class Inner { //内部类,成员内部类
public int a = 5;
}
public static void main(String[] args) {
Test t = new Test();//5
//正常情况是要应该是Test.Inner
Inner r = t.new Inner();
System.out.println(r.a);//5
}
}