内部类
概述
把类定义在其他类的内部,我们称之为内部类
特点
1、内部类可以访问外部类的成员,包括私有
2、外部类要想访问内部类的成员,必须要创建内部类的对象
代码示例
class Outer{
private int num = 10;
class Inner{
public void show(){
System.out.println(num);
}
}
public void fun(){ //利用方法创建对象
// show();//不能直接调用
//创建内部类对象
Inner inner = new Inner();
inner.show();
}
}
public class InnerClassDemo1 {
public static void main(String[] args) {
//创建外部类对象调用fun方法
Outer outer = new Outer();
// outer.show();//不能直接访问
outer.fun();
}
}
分类
按照内部类在类中定义的位置不同,可以分为如下两种格式:
成员位置(成员内部类)
局部位置(局部内部类)
class Outer2{
//定义在成员的位置上(成员内部类)
class Inner2{
}
public void fun(){
//定义在局部范围内(局部内部类)
class Inner3{
}
}
}
成员内部类:
1、定义在类的成员位置上(联想成员变量的位置)
2、内部类可以方法外部类的成员,包括私有的
3、正确创建成员内部类对象的格式:
外部类名.成员内部类名 对象名 = new 外部类名().new 成员内部类名();
class Outer3{
private int num = 10;
class Inner{ //成员内部类
public void show(){
System.out.println(num);
}
}
}
public class InnerClassDemo3 {
public static void main(String[] args) {
//需求:我现在要想在测试类中访问到Inner类中的show方法,咋办,就必须得创建对象
// Inner inner3 = new Inner();//外部不能直接new
//正确创建成员内部类对象的格式
//外部类名.成员内部类名 对象名 = new 外部类名().new 成员内部类名();
// Outer3.Inner oi3 = new Outer3().new Inner();
// oi3.show();//10
//分开写:
Outer3 outer3 = new Outer3();
Outer3.Inner inner = outer3.new Inner();
inner.show();
}
}
成员内部类常见的修饰符:
1、private: 其他类不能直接创建内部类的对象,要想使用被private修饰内部类成员,必须在本类中间接的创建对象调用
2、static: 内部类如果是被static修饰的时候,只能访问外部类中静态成员
3、当内部类是被静态所修饰的时候,出现了另外一种创建内部类的方式
格式如下:
外部类名.内部类名 对象名 = new 外部类名.内部类名(); Outer4.Inner4 oi4 = new
Outer4.Inner4(); 也可以直接通过类名直接调用 Outer4.Inner4.fun();
局部内部类:
1、定义在方法中的类
2、局部内部类可以直接方法外部类中所有成员
3、要想使用局部内部类中的方法,在定义局部内部类的成员方法中,创建局部内部类对象调用方法。
4、在局部内部类中引用的本地的变量必须是最终变量或者实际上的最终变量,局部内部类的方法中定义的局部变量自动加上了final关键字:
因为局部变量会随着方法的调用完毕而消失,这个时候,局部对象并没有立马从堆内存中消失,还要使用那个变量。为了让数据还能继续被使用,就用fianl修饰,这样,在堆内存里面存储的其实是一个常量值。
class Outer6{
private int num = 10;
public void fun(){
int num2 = 20;
class Inner6{ //内部类
int num3 = 300;
public void show(){
num3 = 30;
//在局部内部类中引用的本地的变量必须是最终变量或者实际上的最终变量
//通过反编译工具观察发现,存在局部内部类的方法中定义的局部变量自动加上了final关键字
//在JDK1.8之后会自动加上final关键字
// num2 = 22;//局部变量不可更改
num = 44;
System.out.println(num);
System.out.println(num2);
System.out.println(num3);
}
}
Inner6 inner6 = new Inner6();//在定义局部内部类的成员方法中,创建局部内部类对象调用方法
inner6.show();
}
}
public class InnerClassDemo6 {
public static void main(String[] args) {
Outer6 outer6 = new Outer6();
outer6.fun();
}
}
匿名内部类:
语句定义格式:
new 类名(可以是抽象类也可以具体的类)/接口(){
要重写的方法;
};
这个整体相当于父类的子类对象 或 接口的实现类
举例:
A a = new A(){
b(){…}
c(){…}
};
匿名内部类存在的前提:
要存在一个类或者是一个接口,这个类可以是具体的类也可以是抽象的类
class Outer7{
public void fun(){
//使用匿名内部类的形式创建对象调用show方法
new Inter(){
@Override
public void show() {
System.out.println("这是show方法");
}
@Override
public void show2() {
System.out.println("这是show2方法");
}
}.show();
//使用匿名内部类的形式创建对象调用show2方法
new Inter(){
@Override
public void show() {
System.out.println("这是show方法");
}
@Override
public void show2() {
System.out.println("这是show2方法");
}
}.show2();
System.out.println("======================================");
//想一想,我现在的接口中,只有两个方法,方法的个数比较少,没调用一个方法,都要new一下,并且new之后的内容都是一样的
//如果以后接口中的方法很多的时候,你再用这样的方法,就会很麻烦
//怎么改进呢?
//利用接口多态的形式给匿名内部类起名字
Inter inter = new Inter(){ // 取一个名字接收,相当于Inter i=new B();
@Override
public void show() {
System.out.println("这是show方法");
}
@Override
public void show2() {
System.out.println("这是show2方法");
}
};
inter.show();
inter.show2();
}
}
匿名内部类在开发中的应用:匿名内部类就是子类匿名对象
/*
以前创建子类实现接口进行实例化
*/
//定义一个接口
interface Person2{
public abstract void study();
}
class PersonDemo{
//引用数据类型定义成员变量
Person2 person2;
//无参构造方法
// public PersonDemo() {
// }
//有参构造方法
public PersonDemo(Person2 person2) {
this.person2 = person2;
}
//定义成员方法,引用数据类型进行传参
public void fun(Person2 person){
person.study();
}
}
//创建一个子类实现接口
class Student implements Person2{
@Override
public void study() {
System.out.println("好好学习");
}
}
public class InnerClassDemo1 {
public static void main(String[] args) {
Student student = new Student();
PersonDemo personDemo = new PersonDemo(student); //必须传参数,因为写了带参构造方法,系统就不提供无参构造方法了
personDemo.fun(student);
}
}
//利用匿名内部类的形式创建对象
Person2 person2=new Person2(){ //左侧接口进行接收,右侧new接口或者抽象类
@Override
public void study() {
System.out.println("好好学习");
}
};
person2.study();
//使用匿名内部类进行传参(有 无参构造方法时)
PersonDemo personDemo=new PersonDemo();
personDemo.fun(new Person2() {
@Override
public void study() {
System.out.println("好好学习2");
}
});
//使用匿名内部类进行传参(没有 无参构造方法时)
new PersonDemo(new Person2() {
@Override
public void study() {
System.out.println("这是匿名内部类使用带参构造方法");
}
}).fun(new Person2() {
@Override
public void study() {
System.out.println("好好学习2");
}
});//匿名对象调用了一个fun方法
new PersonDemo(new Person2() {
@Override
public void study() {
System.out.println("这是匿名内部类使用带参构造方法");
}
}).person2.study(); //这里调用的是成员变量中的study方法
面试题
interface Inter { void show(); }
class Outer { //补齐代码 }
class OuterDemo {
public static void main(String[] args) {
Outer.method().show();
}
}
要求在控制台输出”HelloWorld”
分析:
1、根据main方法调用的代码推出第一个结论:method()是静态的,可以直接通过类名访问/调用
2、根据main方法中调用完method()方法之后,还能继续调用方法,我们判定method()是有返回值的
3、再观察后发现,show()方法恰好是Inter2接口中的方法,所以返回值类型是接口Inter2类型
4、根据调用method()方法的参数是空,所以判定method()方法没有参数
public static Inter2 method(){
return new Inter2() {
@Override
public void show() {
System.out.println("HelloWorld");
}
};