前面提到,如果形式参数是接口,传统的方式是提供接口的子实现类来实现接口多态,但是在实际开发中经常使用内部类的方式,这种方式不需要提供子实现类,我们这节就来学习一下内部类。
先通过一个例子来感受一下内部类:
在没有内部类之前:
interface Inter2{
public abstract void study();
}
//具体类
class StudentDemo{
public void method(Inter2 i) {//Inter2 i = new Inter2() ;//错误
i.study();
}
}
class InterImpl2 implements Inter2{
@Override
public void study() {
System.out.println("好好学习,天天向上...");
}
}
//测试类
public class Demo {
public static void main(String[] args) {
//需求:需要调用StudentDemo这个类中method()方法
StudentDemo sd = new StudentDemo() ;
//接口多态的形式
Inter2 i = new InterImpl2() ;
sd.method(i);
}
}
用内部类的方法:
interface Inter2{
public abstract void study();
}
//具体类
class StudentDemo{
public void method(Inter2 i) {//Inter2 i = new Inter2() ;//错误
i.study();
}
}
//测试类
public class Demo {
public static void main(String[] args) {
//需求:需要调用StudentDemo这个类中method()方法
StudentDemo sd = new StudentDemo() ;
Inter2 i2 = new Inter2() {
@Override
public void study() {
System.out.println("好好学习,天天向上...");
}
};
sd.method(i2);
}
}
一、内部类的概念
内部类:
在B类内部定义A类,A类就属于B的内部类
内部类访问外部类的特点:
它可以直接访问外部类的成员,包括私有
外部类如何访问内部类的成员?
通过创建内部类对象的方式间接访问...
class Outer{
int num = 100 ;
private int num2 = 200 ;
//Inner就是Outer的内部类
class Inner{
//内部类的方法
public void show() {
System.out.println(num);
System.out.println(num2);
}
}
//外部类的成员位置
public void method() {
// show() ;
//只能创建内部类对象的方式
Inner i = new Inner() ;
i.show();
}
}
//测试类
public class OuterDemo {
public static void main(String[] args) {
}
}
可以看出,在内部类中打印num和num2都没有问题,说明内部类可以直接访问外部类的成员,包括私有。
而在外部类的成员方法中直接调用内部类的show方法则会报错,说明外部类不能直接访问内部类的成员,如果要调用,只能采取在外部类中创建内部类对象的方式来间接访问。
二、内部类的分类
根据内部类的位置,可以将内部类分为两类:成员内部类和局部内部类
成员内部类:在外部类的成员位置
局部内部类:在外部类的局部位置
class Outer2{
//在成员位置:成员内部类
//class Inner2{
//
//}
public void method() {
//在局部位置:局部内部类
class Inner{
}
}
}
1、成员内部类
成员内部类:
可以直接外部类的成员,包括私有
外部类要访问内部类(非静态的内部类)的成员方法:格式:外部类名.内部类名 对象名 = new 外部类对象.new内部类对象
我们通过具体代码来感受一下:
class Outer3{
//外部类的成员变量
private int num = 10 ;
//成员内部类
class Inner3{
//show()
public void show() {
System.out.println(num);//成员内部类可以直接访问外部类的成员,包括私有
}
}
}
//测试类
public class OuterDemo3 {
public static void main(String[] args) {
//格式:外部类名.内部类名 对象名 = new 外部类对象.new 内部类对象
Outer3.Inner3 oi = new Outer3().new Inner3();
oi.show();
}
}
关于成员内部类的修饰符:
private: 作用:保证数据的安全性!
static修饰:可以把静态内部类看成是外部类的成员.
特点:
静态成员内部类访问外部类的数据,该数据必须static修饰
外部类要访问内部类(静态)的成员方法:
格式:外部类名.内部类名 对象名 = new 外部类对象.内部类对象
class Outer4{
private int num = 10 ;
private static int num2 = 100 ;
//成员内部类:静态的
static class Inner4{
//成员方法
//非静态的内部类成员方法
public void show() {
//System.out.println(num); //静态成员内部类访问外部类的数据,该数据必须static修饰
System.out.println(num2);
}
//静态的内部类的成员方法
public static void show2() {
//System.out.println(num);
System.out.println(num2);
}
}
}
//测试类
public class OuterDemo4 {
public static void main(String[] args) {
//对于静态的成员内部类的访问格式
//外部类名.内部类名 对象名 = new 外部类名.内部类名() ; //把静态的成员内部类看成了外部类的成员
Outer4.Inner4 oi = new Outer4.Inner4() ;
oi.show();
oi.show2();
}
}
由于静态成员内部类访问外部类的数据,该数据必须static修饰,无论该方法是否为静态方法,所以只能打印静态的num2值,打印num则会报错,外部类要访问静态的内部类时,需要特定的访问格式:外部类名.内部类名 对象名 =new 外部类名.内部类名() ;此时把静态的成员内部看成了外部类的成员,可以通过类名直接调用。
2、局部内部类
局部内部类
可以访问外部类的成员包括私有...
在外部类的局部位置去访问内部类的show( ),需要在局部位置创建内部类对象,通过对象去访问
//定义外部类
class Outer5{
private int num = 10 ;
//定义外部类的成员方法
public void method() {
//变量
final int num2 = 20 ; //jdk1.8不会有问题..
//定义局部内部类
class Inner5{
public void show() {
System.out.println(num);
//注意事项:在这块改变量继续被使用...将变量变成固定值:在内存始终存在(被内部类的成员去使用)
System.out.println(num2);
}
}
//创建对象
Inner5 i = new Inner5() ;
i.show(); //调用show()
}
}
public class OuterDemo5 {
public static void main(String[] args) {
//创建对象
Outer5 o = new Outer5() ;
o.method();
}
}
三、匿名内部类
前提是有一个类或者接口
这个类可以是具体类也可以是抽象类
new 类名或者接口名{
方法重写();
}
匿名内部类的本质:
是继承了该类或者实现了该接口子类对象...
//定义一个接口
interface Inter{
public abstract void show();
public abstract void show2() ;
}
//定义一个类实现这接口...
class Outer6{
//成员方法
public void method() {
//调用接口一个方法的时候:匿名内部类的形式
//两个方法调用
/* new Inter() {
@Override
public void show2() {
System.out.println("show2....");
}
@Override
public void show() {
System.out.println("show...");
}
}.show();
new Inter() {
@Override
public void show2() {
System.out.println("show2....");
}
@Override
public void show() {
System.out.println("show...");
}
}.show2();*/
//上述非常麻烦:直接创建对象,给它起名字
Inter i = new Inter() {
@Override
public void show2() {
System.out.println("show2...");
}
@Override
public void show() {
System.out.println("show....");
}
};
i.show();
i.show2();
}
}
public class OuterDemo6 {
public static void main(String[] args) {
//创建Outer6类的对象
Outer6 o = new Outer6() ;
o.method();
}
}
一道匿名内部类面试题:
按照要求,补齐代码
interface Inter { void show(); }
class Outer { //补齐代码 }
class OuterDemo {
public static void main(String[] args) {
Outer.method().show();
}
}
要求在控制台输出”HelloWorld”
分析:
Outer.method().show(); ---->Outer.method() :当前这个method方法是静态方法(因为可以直接通过类名调用)
因为可以直接调show方法:Outer.method().show();---->Outer.method()返回一个对象.show()---->由于show()方法是一个接口中的方法,返回值是一个接口类型,当前并不提供接口的子实现类,所以只能用匿名内部类
代码如下:
interface Inter { void show(); }
class Outer { //补齐代码
public static Inter method() {
return new Inter() {
@Override
public void show() {
System.out.println("HelloWorld");
}
};
}
}
class OuterDemo {
public static void main(String[] args) {
Outer.method().show();
}
}
至此,面向对象部分结束。