8. 面向对象编程 8.9 內部类
8. 面向对象编程
8.9 內部类
如果定义类在局部位置(方法中/代码块):(1) 局部内部类 (2) 匿名内部类
定义在成员位置 (1) 成员内部类 (2) 静态内部类
8.9.1基本介绍
一个类的内部又完整的嵌套了另一个类结构。被嵌套的类称为內部类,嵌套其他类的类称为外部类。是类的第五大成员。【思考:类的五大成员是哪些?[属性、方法、构造器、代码块、内部类] 】,内部类最大的特点就是可以直接访问私有属性,并且可以体现类与类之间的包含关系,注意:内部类是学习的难点,同时也是重点,后面看底层源码时,有大量的内部类。
8.9.2 基本语法
class Outer{ //外部类
class Inner{ //内部类
}
}
class Other{ //外部其他类
}
//InnerClass01.java
8.9.3快速入门案例
代码
package com.ming.innerclass;
public class InnerClass01 {
public static void main(String[] args) {
}
}
class Outer{//外部类
private int n1 = 100;//属性
public Outer(int n1){//构造器
this.n1 = n1;
}
{//代码块
System.out.println("代码块");
}
class Inner{//內部类,在Outer类的内部
}
}
8.9.4 内部类的分类
定义在外部类局部位置上(比如方法内):
- 局部内部类(有类名)
- 匿名内部类(没有类名,重点!!!!!!!!)
定义在外部类的成员位置上:
- 成员内部类(没用static修饰)
- 静态内部类(使用static修饰)
8.9.5 局部内部类的使用 LocalInnerClass.java
说明:局部内部类是定义在外部类的局部位置,比如方法中,并且有类名。
-
可以直接访问外部类的所有成员,包含私有的
-
不能添加访问修饰符,因为它的地位就是一个局部变量。局部变量是不能使用修饰符的。但是可以使用final修饰,因为局部变量也可以使用final
-
作用域:仅仅在定义它的方法或代码块中。
-
局部内部类----访问----->外部类的成员 [访问方式:直接访问]
-
外部类----访问----->局部内部类的成员
访问方式:创建对象,再访问(注意:必须在作用域内)
记住:
(1)局部内部类定义在方法中/代码块
(2)作用域在方法体或者代码块中
(3)本质仍然是一个类
- 外部其他类---不能访问----->局部内部类(因为 局部内部类地位是一个局部变量)
- 如果外部类和局部内部类的成员重名时,默认遵循就近原则,如果想访问外部类的成员,则可以使用(外部类名.this.成员)去访问【演示】
System.out.println("外部类的n2=" + 外部类名.this.n2);
package com.ming.innerclass;
/*
* 演示局部内部类的使用
* */
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.可以直接访问外部类的所有成员,包含私有的
//7.如果外部类和局部內部类的成员重名是,默认遵循就近原则
//如果想访问外部类的成员,使用外部类名.this.成员去访问
private int n1 = 800;
public void f1(){
System.out.println("n1=" + Outer02.this.n1);
System.out.println("Outer02.this)" + Outer02.this);
m2();
}
}
//5.外部类在方法中,可以创建Inner02对象,然后调用方法即可
Inner02 inner02 = new Inner02();
inner02.f1();
}
{//代码块
class Inner03 {
}
}
}
8.9.6 匿名内部类的使用(重要!!!!!!!)
(1)本质是类、(2)内部类(3)无名字(4)同时是一个对象
定义在外部类的局部位置(如方法中 )
- 基本语法:`new 类或接口(参数列表){ 类体 };
案例演示关联文件:AnonymousInnerClass.java
package com.ming.innerclass;
public class AnonymousInnerClass {
public static void main(String[] args) {
new Outer04().method();
}
}
class Outer04{//外部类
private int n1 = 10;
public void method() {
//基于接口的匿名内部类
//1.需求:想使用IA接口
//2.传统方式,是写一个类实现接口并创建对象
//3.现在需求是Tiger类只使用一次,后面不再使用
//4.可以使用匿名內部类来简化开发
//5.tiger 的编译类型 是 IA
//6.tiger 的运行类型 是 匿名內部类
/*
我们看底层 会分配类名 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 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 father = new Father("jack"){
@Override
public void test() {
super.test();
System.out.println("匿名內部类重写类test方法");
}
};
System.out.println("father对象的运行类型 = "+father.getClass());
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 Father{
public Father(String name){
System.out.println("接受的name = " + name);
}
public void test(){
System.out.println("我是父类的test()");
}
}
abstract class Animal{
abstract void eat();
}
AnonymousInnerClassDetail.java
2. 匿名内部类的语法比较奇特,请大家注意,因为匿名内部类既是一个类的定义,同时它本身也是一个对象,因此从语法上看,它既有定义类的特征,也有创建对象的特征,对前面代码分析可以看出这个特点,因此可以调用匿名内部类方法。
-
可以直接访问外部类的所有成员,包含私有的 [案例演示]
-
不能添加访问修饰符,因为它的地位就是一个局部变量。[过]
-
作用域:仅仅在定义它的方法或代码块中。[过]
-
匿名内部类----访问----->外部类成员 [访问方式:直接访问]
-
外部其他类---不能访问----->匿名内部类(因为 匿名内部类地位是一个局部变量)
-
如果外部类和匿名内部类的成员重名时,匿名内部类访问的话,默认遵循就近原则,如果想访问外部类的成员,则可以使用(外部类名.this.成员)去访问
package com.ming.innerclass;
public class AnonymousInnerClassDetail {
public static void main(String[] args) {
Outer05 outer05 = new Outer05();
outer05.f1();
System.out.println("outer05 的hashCode值" + outer05);
}
}
class Outer05 {
private int n1 = 99;
public void f1(){
//创建一个基于类的匿名內部类
Person p = new Person(){
private int n1 = 666;
//可以直接访问外部类的所有成员,包含私有的
//不能添加访问修饰符,因为作用就是一个局部变量
//作用域仅在定义它的代码块和方法体中
//如果外部类和局部內部类的成员重名是,默认遵循就近原则
//如果想访问外部类的成员,使用外部类名.this.成员去访问
@Override
public void hi() {
System.out.println("匿名內部类重写了hi方法 n1 = " + Outer05.this.n1);
//Outer05.this就是调用f1的对象
System.out.println("Outer05.this 的hashCode值" + Outer05.this);
}
};
p.hi();//动态绑定,运行类型是 Ourer05$1
//也可以直接调用 匿名內部类.方法
//class 匿名內部类 extends Person{}
new Person(){
@Override
public void hi() {
System.out.println("匿名內部类重写了hi方法");
}
@Override
public void ok(String str) {
super.ok(str);
}
}.ok("45646");
}
}
class Person {//类
public void hi(){
System.out.println("Person hi()");
}
public void ok(String str){
System.out.println("Person ok()" + str);
}
}
8.9.7匿名内部类的最佳实践
当做实参直接传递,简洁高效。InnerClassExercise02.java
package com.ming.innerclass;
public class InnerClassExercise02 {
public static void main(String[] args) {
CellPhone cellPhone = new CellPhone();
cellPhone.alarmClock(new Bell() {
@Override
public void ring() {
System.out.println("懒人起床了");
}
});
cellPhone.alarmClock(new Bell() {
@Override
public void ring() {
System.out.println("同学们上课了");
}
});
}
}
interface Bell{
void ring();
}
class CellPhone{
public void alarmClock(Bell bell){
bell.ring();
}
}
8.9.9 成员内部类的使用
MemberInnerClass01.java
说明:成员内部类是定义在外部类的成员位置,并且没有static修饰。
- 可以直接访问外部类的所有成员,包含私有的
class Outer01{//外部类
private int n1 = 10;
public String name = "张三";
class Inner01{
public void say(){
System.out.println("Outer01 的 n1 = " + n1 + " outer01 的 name = " + name );
}
}
}
-
可以添加任意访问修饰符(public、protected、默认、private),因为它的地位就是一个成员。
-
作用域 MemberInnerClass01.java
和外部类的其他成员一样,为整个类体
比如前面案例,在外部类的成员方法中创建成员内部类对象,再调用方法. -
成员内部类----访问----->外部类成员(比如:属性) [访问方式: 直接访问] (说明)
-
外部类----访问------->成员内部类 (说明)
访问方式: 创建对象,再访问 -
外部其他类----访问----->成员内部类
-
如果外部类和内部类的成员重名时,内部类访问的话,默认遵循就近原则,如果想访问外部类的成员,则可以使用 (外部类名.this.成员) 去访问
package com.ming.innerclass;
public class MemberInnerClass01 {
public static void main(String[] args) {
Outer08 outer08 = new Outer08();
outer08.t1();
//外部其他类,使用成员內部类的三种方式
//第一种方式
//outer08.new Inner08();相当于把把new Inner08()当作outer08的成员
//这就是一个语法,不用特别纠结
Outer08.Inner08 inner08 = outer08.new Inner08();
inner08.say();
//第二种方式 在外部类中编写一个方法,可以返回Inner08对象
Outer08.Inner08 inner08Instance = outer08.getInner08();
inner08Instance.say();
//第三种
new Outer08().new Inner08();
}
}
class Outer08{
private int n1 = 10;
public String name = "张三";
public void hi(){
System.out.println("hi()方法...");
}
//1.注意:成员內部类,是定义在外部类的成员位置上
//2.可以添加任意访问修饰符(public,protected,默认,private)
class Inner08{//成员內部类
//如果外部类和局部內部类的成员重名是,默认遵循就近原则
//如果想访问外部类的成员,使用外部类名.this.成员去访问
private int n1 = 66;
private double sal = 99.8;
public void say(){
System.out.println("n1=" + Outer08.this.n1+" name="+name);
hi();
}
}
//方法返回一个Inner08的实例
public Inner08 getInner08(){
return new Inner08();
}
//写方法
public void t1(){
//使用成员内部类
//创建成员内部类对象,然后使用相关方法
Inner08 inner08 = new Inner08();
inner08.say();
System.out.println("inner08.sal="+inner08.sal);
}
}
8.9.10 静态内部类的使用 StaticInnerClass01.java
说明:静态内部类是定义在外部类的成员位置,并且有static修饰
- 可以直接访问外部类的所有静态成员,包含私有的,但不能直接访问非静态成员
- 可以添加任意访问修饰符(public、protected、默认、private),因为它的地位就是一个成员。
- 作用域:同其他的成员,为整个类体
- 静态内部类----访问---->外部类(比如:静态属性) [访问方式:直接访问所有静态成员]
- 外部类----访问------>静态内部类 访问方式:创建对象,再访问
- 外部其他类----访问----->静态内部类
- 如果外部类和静态内部类的成员重名时,静态内部类访问的时,默认遵循就近原则,如果想访问外部类的成员,则可以使用(外部类名.成员)去访问
package com.ming.innerclass;
public class StaticnnerClass01 {
public static void main(String[] args) {
Outer10 outer10 = new Outer10();
outer10.m1();
//外部其他类使用 静态内部类
//方式一
//因为静态内部类,是可以通过类名直接访问(前提是满足访问权限)
Outer10.Inner10 inner10 = new Outer10.Inner10();
inner10.say();
//方式二
// 在外部类中编写一个方法,可以返回Inner10对象实例
Outer10.Inner10 inner11 = outer10.getInner10();
inner11.say();
Outer10.Inner10 inner10static = Outer10.getInner10static();
inner10static.say();
}
}
class Outer10{
private int n1 = 10;
private static String name = "张三";
//Inner10就是静态内部类
//1.放在外部类的成员位置
//2.使用static修饰
//3.可以直接访问外部类的所有静态成员,包含私有的,但不能直接访问非私有的
//4.可以添加任意访问修饰符
//5.作用域 :同其他的成员,为整个类体
static class Inner10{
private static String name = "李四";
public void say(){
//如果外部类和局部內部类的成员重名是,默认遵循就近原则
//如果想访问外部类的成员,使用外部类名.成员去访问
System.out.println(name);
System.out.println(Outer10.name);
}
}
public void m1(){
Inner10 inner10 = new Inner10();
inner10.say();
}
public Inner10 getInner10(){
return new Inner10();
}
public static Inner10 getInner10static(){
return new Inner10();
}
}