内部类
大约 6 分钟
内部类
基本介绍
一个类的内部又完整的嵌套了另一个类结构。被嵌套的类称为**内部类(inner class)**嵌套其他类的类称为外部类 (outer class) 。是我们类的第五大成员,内部类最大的特点就是可以直接访问私有属性,并且可以体现类与类之间的包含关系
思考: 类的五大成员是哪些?
属性、方法、构造器、代码块、内部类,
基本语法
/** 外部类 */
class Outer{
/** 内部类 */
class Inner{}
}
class Other {} /** 外部其他类 */
内部类的分类
定义在外部类局部位置上 (比如方法内)
- 局部内部类(有类名)
- 匿名内部类(没有类名,重)
定义在外部类的成员位置上
- 成员内部类(没用 static 修饰)
- 静态内部类(使用 static 修饰)
局部内部类的使用
说明: 局部内部类是定义在外部类的局部位置,比如方法中,并且有类名
- 可以直接访问外部类的所有成员,包含私有的
- 不能添加访问修饰符,因为它的地位就是一个局部变量。局部变量是不能使用修饰符的。但是可以使用 final 修饰,因为局部变量也可以使用final
- 作用域: 仅仅在定义它的方法或代码块中。
- 局部内部类---访问---->外部类的成员【访问方式: 直接访问】
- 外部类---访问---->局部内部类的成员【访问方式:创建对象,再访问(注意:必须在作用域内)】
public class LocalInnerClass01 { public static void main(String[] args) { Outer02 outer02 = new Outer02(); outer02.m1(); } } class Outer02 { /** 私有属性和方法 */ private int n1 = 100; private void m2() { System.out.println("Outer + m2方法"); } public void m1(){ /** 内部类通常在方法里面,他本身也是一个类 */ class Inner02 { public void f1(){ /** 内部类可以直接访问外部类的所有成员 */ System.out.println("n1= " + n1); m2(); } } /** 可以家加 final 修饰符 */ final class Inner03 {} class Inner04 extends Inner02 { public void f2(){} } /** 外部类在方法中,可以创建对象,然后调用方法即可 */ Inner03 inner03 = new Inner03(); Inner02 inner02 = new Inner02(); Inner04 inner04 = new Inner04(); inner02.f1(); inner04.f2(); } /** 代码块中的内部类 */ { class Inner05 {} } }
- 外部其他类不能访问局部内部类( 局部内部类地位是一个局部变量)
- 外部类和局部内部类的成员重名时,默认遵循就近原则,如果想访问外部类的成员,则可以使用 (外部类名.this.成员)去访问[演示]
public class LocalInnerClass01 { public static void main(String[] args) { Outer02 outer02 = new Outer02(); outer02.m1(); } } class Outer02 { private int n1 = 100; public void m1(){ class Inner02 { private int n1 = 800; public void f1(){ System.out.println("内部类 " + n1 + " 外部类" + Outer02.this.n1); } } }
匿名内部类的使用(重要!!!!!!!)
说明: 匿名内部类是定义在外部类的局部位置,比如方法中,并且没有类名
- 本质是类
- 内部类
- 该类没有名字
- 同时还是一个对象
基本语法
new 类或接口(参数列表){
类体
}
演示(基于接口)
需求(为什么使用匿名类):想使用接口 PP 并创建对象
传统方式
写一个类,实现接口, 并创建对象
public class Anonymous {
public static void main(String[] args) {
Outer04 outer04 = new Outer04();
outer04.method();
}
}
class Outer04 {
private int n1 = 10;
public void method(){
/**
* 需求是 Tiger 只使用一次,后面不适用
* 所以使用内部类来简化
**/
Tiger tiger = new Tiger();
Dog dog = new Dog();
tiger.cry();
dog.cry();
}
}
/** 接口 */
interface PP{
public void cry();
}
/** 实现接口 */
class Tiger implements PP{
@Override
public void cry() {
System.out.println("传统方式实现接口 Tiger");
}
}
class Dog implements PP{
@Override
public void cry() {
System.out.println("传统方式实现接口 Dog");
}
}
匿名类实现
public class Anonymous {
public static void main(String[] args) {
Outer04 outer04 = new Outer04();
outer04.method();
}
}
class Outer04 {
private int n1 = 10;
public void method(){
/**
* 1. 需求是 Tiger 只使用一次,后面不适用
* 2. 所以使用内部类来简化
* 3. taiger 的编译类型?
* 4. taiger 的运行类型? 匿名类(Outer04$1)【匿名类名字是:类名+$1】
* 5. jdk底层在创建匿名内部类 Outer04$1,立即马上就创建了 outer04S1实例,并且把地址返回给 tiger
* 6. 匿名内部类使用一次,就不能再使用
**/
PP taiger = new PP() {
@Override
public void cry() {
System.out.println("老虎交换");
}
};
System.out.println("taiger的运行类型=" + taiger.getClass());
taiger.cry();
}
}
/** 接口 */
interface PP{
public void cry();
}
演示(基于类)
public class Anonymous {
public static void main(String[] args) {
Outer04 outer04 = new Outer04();
outer04.method();
}
}
class Outer04 {
private int n1 = 10;
public void method(){
/**
* 1. father 的编译类型? Father
* 2. father 的运行类型? 匿名类(Outer04$1)【匿名类名字是:类名+$1】
* 3. jdk底层在创建匿名内部类 Outer04$1,立即马上就创建了 outer04S1实例,并且把地址返回给 father
**/
Father father = new Father("JACK"){};
System.out.println("father的运行类型=" + father.getClass());
father.test01();
/** 匿名类也可以直接调用 */
new Father("JACK"){}.test01();
}
}
class Father{
public Father(String name){
super();
}
public void test01(){
System.out.println("老虎交换");
}
}
实践简化
public class Anonymous {
public static void main(String[] args) {
f1(new PP() {
@Override
public void cry() {
System.out.println("实践简化");
}
});
}
public static void f1(PP pp){
pp.cry();
}
}
/** 接口 */
interface PP{
void cry();
}
public class Anonymous {
public static void main(String[] args) {
f1(new Picrure());
}
}
/** 接口 */
interface PP{
void cry();
}
class Picrure implements PP {
@Override
public void cry() {
System.out.println("实现接口传参");
}
}
成员内部类
说明: 成员内部类是定义在外部类的成员位置,并且没有 static 修饰
- 1.可以直接访问外部类的所有成员,包含私有的
- 可以添加任意访问修饰符( public、protected 、默认、private),因为它的地位就是一个成员。
- 作用:和外部类的其他成员一样,为整个类体比如前面案例,在外部类的成员方法中创建成员内部类对象,再调用方法
- 成员内部类---访问---->外部类(比如: 属性)[访问方式:直接访间]
- 外部类---访问------>内部类 访问方式: 创建对象,再访问
- 外部其他类---访问---->成员内部类
- 如果外部类和内部类的成员重名时,内部类访问的话,默认遵循就近原则,如果想访问外部类的成员,则可以使用(外部类名.this.成员)去访问
演示
public class Outer08 {
public static void main(String[] args) {
// 1.使用外部类,调用内部类方法
Inner08 inner08 = new Inner08();
inner08.says();
// 2.直接实例化内部类
Inner08.InnerClass innerClass = inner08.new InnerClass();
innerClass.say();
// 3.直接使用方法返回的实例
Inner08.InnerClass innerClass1 = inner08.getInnerClass();
innerClass1.say();
}
}
class Inner08 {
private int n2 = 10;
public String name = "账单";
class InnerClass {
public void say(){
System.out.println(n2 + name);
}
}
public void says(){
// 外部类方法实例化内部类
InnerClass innerClass = new InnerClass();
innerClass.say();
}
// 该方法返回内部类实例
public InnerClass getInnerClass(){
return new InnerClass();
}
}
静态内部类
说明: 静态内部类是定义在外部类的成员位置,并且有 static 修饰
- 可以直接访问外部类的所有静态成员,包含私有的,但不能直接访问非静态成员
- 可以添加任意访问修饰符(public、protected 、默认、private),因为它的地位就是个成员。
- 作用域: 同其他的成员,为整个类体
- 静态内部类---访问---->外部类(比如: 静态属性)[访问方式: 直接访问所有静态成员]
- 外部类---访问--->静态内部类 访问方式:创建对象,再访问
演示
public class Outher10 {
public static void main(String[] args) {
InnerClass10.Inner10 inner10 = new InnerClass10.Inner10();
inner10.scy();
}
}
class InnerClass10 {
private int n1 = 10;
private static String name = "JJJJ";
static class Inner10 {
public void scy(){
System.out.println(name);
}
}
}
小结
内部类有四种
- 局部内部类
- 匿名内部类
- 成员内部类
- 静态内部类
注意
成员内部类,静态内部类,是放在外部类的成员位置,本质就是一个成