一·内部类的基本介绍
1.概念
1.定义在外部类的里面
2.代码及讲解
package innerclass;
public class Innerclass01 {//外部其他类
public static void main(String[] args) {
// TODO 自动生成的方法存根
}
}
class Outer{//外部类
private int n1=100;//属性
public Outer(int n1) {//代码
super();
this.n1 = n1;
}
public void m1()//构造器
{
System.out.println("m1()");
}
{//代码块
System.out.println("代码块~~");
}
class Inner{//内部类,在Outer类的内部
}
}
上面的Inner就是一个内部类,Outer是外部类,而Innerclass01则是外部其他类
二·定义在局部的内部类
1.局部内部类
1.概念
1.定义在局部位置的内部类(有类名)
2.代码
package innerclass;
public class Innerclass02 {//外部其他类
/*
* 演示局部内部类的使用
*/
public static void main(String[] args) {
// TODO 自动生成的方法存根
Outer02 outer02=new Outer02();
outer02.m1();
//6.外部其他类不能访问局部内部类(因为局部内部类地位是一个局部变量)
Outer06 outer06=new Outer06();
outer06.m1();
}
}
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就是哪个对象
//此时这个 Outer02.this 就是上面的 outer02
System.out.println("n1="+n1+"\t外部类的n1="+Outer02.this.n1);
m2();
}
}
// class Inner03 extends Inner02{//可以使用final修饰Inner02,Inner03不能继承
//
// }
//6.外部类在方法中,可以创建Inner02对象,然后调用方法即可
Inner02 inner02=new Inner02();
inner02.f1();
System.out.println(inner02.n1);
}
{//代码块
class Inner04{
}
}
}
class Outer06 extends Outer02//可以被继承
{
}
上面的Inner02就是一个局部内部类
3.使用细节
根据上面代码分析
1.局部内部类可以直接访问外部类的所有成员,包含私有的,在上面的Inner02的f1()中就可以直接调用Outer02的m2()方法
2.不能添加访问修饰符(public,private···),但是可以用final修饰局部类内部类
3.作用域:在定义它的方法或代码块中(局部内部类等价于一个局部变量)
4.外部类访问局部内部类需要创建对象,再访问,比如上面的inner02 对象
5.外部其他类不能访问局部内部类
6.如果局部内部类有成员与外部类重名了,默认遵守就近原则,如果想访问外部类的成员(外部类名.this.成员),比如上面的n1属性在f1()方法中有两种调用方法,分别是默认和( 外部类名.this.成员 )外部类名.this 就相当于一个Outer02的对象。
2.匿名内部类
1.概念
1.定义在局部位置的内部类(“无”类名),编译器帮助你创建的一个类名
2.语法: new 类或接口(参数列表){类体};
2.代码
package innerclass;
public class Inneranonymous {
public static void main(String[] args) {
// TODO 自动生成的方法存根
Outer04 outer04=new Outer04();
outer04.method();
}
}
class Outer04{//外部类
private int n1=10;//属性
public void method()//方法
{
//基于接口的匿名内部类
//1.需求:想使用IA接口,并创建对象
//2.传统方法:写一个类,实现该接口,并创建对象
//3.如果需求是Tiger类只是使用一次,后面不使用
//4.可以使用匿名内部类简化开发
//5.tiger的编译类型? IA
//6.tiger的运行类型是? 就是匿名内部类 XXXX => Outer04$1
/*
* 看底层
* class XXXX implements IA
* {
* @Override
public void cry() {
// TODO 自动生成的方法存根
System.out.println("老虎叫唤~~~");
}
* }
*/
//7.jdk底层在创建匿名内部类 Outer04$1,立即马上就创建了 Outer04$1 实例,并且把地址
//返回给tiger
//8.匿名内部类使用一次,就不能在使用
IA tiger=new IA()
{
@Override
public void cry() {
// TODO 自动生成的方法存根
System.out.println("老虎叫唤~~~");
}
};
System.out.println("tiger的运行类型="+tiger.getClass());
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() {
// TODO 自动生成的方法存根
System.out.println("匿名内部类重写了test方法");
}
}
*/
//4.同时也直接返回了 匿名内部类 Outer04$2的对象
//5.注意("jack") 参数列表会传递给 构造器
Father father=new Father("jack"){
@Override
public void test() {
// TODO 自动生成的方法存根
System.out.println("匿名内部类重写了test方法");
}
};
System.out.println("father的运行类型="+father.getClass());
father.test();
System.out.println(father.getName());
//基于抽象类的 匿名内部类
Animal animal=new Animal()
{
@Override
void eat() {
// TODO 自动生成的方法存根
System.out.println("eat~~~");
}
};
}
}
interface IA{//接口
public void cry();
}
//class Tiger implements IA{
//
// @Override
// public void cry() {
// // TODO 自动生成的方法存根
// System.out.println("老虎叫唤~~~");
// }
//
//}
class Father{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Father(String name)//构造器
{
super();
this.name=name;
}
public void test()
{
}
}
abstract class Animal
{
abstract void eat();
}
上面的IA tiger=new IA(){····};和Father father =new Father(”jack“){·····};还有Animal animal=new Animal(){·····};分别是基于接口和普通类还有抽象类创建的匿名内部类
3.使用细节
1.匿名内部类可以看作是一个对象
package innerclass;
public class Inneranonymous02 {
public static void main(String[] args) {
// TODO 自动生成的方法存根
//当作实参直接传递,简洁高效
f1(new IL(){
@Override
public void show() {
// TODO 自动生成的方法存根
System.out.println("这是一幅名画");
}
});
//传统方法
f1(new Picture());
}
//静态方法
public static void f1(IL il)
{
il.show();
}
}
//接口
interface IL{
void show();
}
class Picture implements IL{
@Override
public void show() {
// TODO 自动生成的方法存根
System.out.println("这是一幅名画");
}
}
从上面的代码中可以看到我们可以将匿名内部类当作一个对象传递,在上面的f1()方法中,我们可以传递一个实现IL接口的匿名内部类,也可以传递一个Picture的对象
2.可以直接访问外部类的所有成员,包含私有的
3.不能添加访问修饰符
5.作用域:仅仅在定义它的方法或代码块中
6.外部其他类不能访问匿名内部类
7.如果匿名内部类有成员与外部类重名了,默认遵守就近原则,如果想访问外部类的成员(外部类名.this.成员)
后面的这几点(2.5.6.7)和局部内部类一样
4.我的理解
1.其实这个匿名内部类和一个对象差不多,具体的话,就是,它的使用场景一般是:当我想要使用一个接口(或类)的方法,你可以创建一个匿名内部类,此时如果是基于接口,抽象类实现的,你需要实现接口,抽象类的所有方法,如果是基于普通类实现的,你可以重写此类的方法也可以不重写,然后,这个匿名内部类就可以作为一个对象去掉这些方法,可以直接调用,也可以将匿名内部类赋给一个对象去调用
三·定义在成员位置的内部类
1.成员内部类
1.概念
1.定义在成员位置的内部类
2.代码
package innerclass;
public class Innermemer {
public static void main(String[] args) {
// TODO 自动生成的方法存根
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.getInner08Instance();
inner08Instance.say();
//第三种方式
}
}
class Outer08{
private int n1=10;
public String name="张三";
private void hi()
{
System.out.println("hi()方法");
}
//2.可以添加任意访问修饰符(public,protected,默认,private),因为它的地位就是一个成员
//3.作用域:整个外部类
class Inner08{
private double sal=99.8;
private int n1=66;
public void say()
{
//1.可以直接访问外部类的所有成员,包含私有的
//如果成员内部类的成员和外部类的成员重名,会遵守就近原则
//可以通过 外部类.this.属性 来访问外部类的成员
System.out.println("n1="+n1+"\tname="+name);
System.out.println("外部类的n1="+Outer08.this.n1);
hi();
}
}
//方法:返回一个Inner08实例
public Inner08 getInner08Instance()
{
return new Inner08();
}
//写方法
public void t1()
{
//使用成员内部类
//创建成员内部类的对象,然后使用相关的方法
Inner08 inner08=new Inner08();
inner08.say();
System.out.println(inner08.sal);
System.out.println();
}
}
上面的Inner08就是一个成员内部类
3.使用细节
1.可以直接访问外部类的所有成员,包含私有的,如果成员内部类的成员和外部类的成员重名,会遵守就近原则,可以通过 外部类.this.属性 来访问外部类的成员,由上面的hi()方法和n1属性体现
2.可以添加任意访问修饰符(public,protected,默认,private)
3.作用域:整个外部类
4.外部类访问成员内部类:写方法,使用成员内部类创建对象,然后使用相关的方法,上面代码的t1()方法
5.外部其他类访问成员内部类在上面的代码的main方法中
2.静态内部类
1.概念
1.定义在成员位置上的静态类
2.代码
package innerclass;
import innerclass.Outer08.Inner08;
public class Innerstatic {
public static void main(String[] args) {
// TODO 自动生成的方法存根
Outer10 outer10=new Outer10();
outer10.m1();
//外部其他类使用静态内部类
//方式一
//因为静态内部类,是可以通过类名直接访问(前提是满足访问权限)
Outer10.Inner10 inner10=new Outer10.Inner10();
//方式二
//编写一个方法可以返回静态内部类实例
Outer10.Inner10 inner101=outer10.getInner10();
System.out.println("=============");
inner101.say();
//也可将该方法改为静态的,通过类名直接调用
//Outer10.Inner10 inner102=Outer10.getInner10();
}
}
class Outer10{//外部类
private int n1=10;
private static String name ="张三";
private static void cry()
{
}
//Inner10就是静态内部类
//1.放在外部类的成员位置
//2.使用static修饰
//3.可以直接访问外部类的所有静态成员,包含私有的,但是不能直接访问非静态成员
//4.可以添加任意访问修饰符(public,protected,默认,private),因为它的地位是一个成员
//5.作用域:同其他的成员,为整个类体
static class Inner10{
private static String name="李四";
//如果外部类和静态内部类的成员重名时,静态内部类访问时
//默认遵守就近原则,如果想访问外部类的成员,则可以使用(外部类名.成员)
public void say()
{
System.out.println(name);
cry();
System.out.println("外部类name="+Outer10.name);
}
}
public void m1()//外部类访问静态内部类的方式:创建对像,再访问
{
Inner10 inner10=new Inner10();
inner10.say();
}
public Inner10 getInner10() {
return new Inner10();
}
}
上面的Inner10就是一个静态内部类
3.使用细节
1.可以直接访问外部类的所有静态成员,包含私有的,但是不能直接访问非静态成员
2.可以添加任意访问修饰符(public,protected,默认,private),因为它的地位是一个成员
3.作用域:同其他的成员,为整个类体
4.如果外部类和静态内部类的成员重名时,静态内部类访问时,默认遵守就近原则,如果想访问外部类的成员,则可以使用(外部类名.成员)
5.外部类访问静态内部类的方式:创建对像,再访问
6.外部其他类访问静态内部类: Outer10.Inner10 inner10=new Outer10.Inner10();我推荐这一种