什么是内部类?
把类定义在其他类的内部,这个类就被称为内部类,内部类可以定义在
类内部
包括类中的任何位置,甚至在方法中也可以定义内部类
内部类的访问特点
-
内部类可以直接访问外部的成员,包括私有
-
外部类要访问内部类的成员必须创建对象
-
内部类提供了更好的封装,可以把内部类隐藏在外部类之内,不允许其他类访问该类
-
匿名内部类适合用于创建哪些仅需要一次使用的类
-
可以由public、private、protected权限修饰符修饰
-
可以使用static修饰内部类
成员内部类
在成员位置(在类中,方法、构造器、代码块以外)定义的类,被称为成员内部类
成员内部类又分为静态内部类和非静态内部类
静态内部类
静态内部类是由static修饰的内部类,当使用static修饰内部类,则内部类属于外部类本身,与静态成员变量类似,在类加载时加载
为什么外部类不支持使用static修饰?
因为外部类的上级程序单位是包,内部类的上级程序单元是外部类
静态内部类的实现及外部类访问:
public class MemberClass {
private String id;
//静态内部类
private static class InnerStaticClass{
private static String name;
private String age;
private void play(){
//无法直接访问
// String str = id;
System.out.println(members+"私有方法");
}
}
//非私有静态内部类
static class StaticClass{
private static String name;
private String age;
private void play(){
//无法直接访问
// String str = id;
System.out.println(members+"私有方法");
}
public void test(){
System.out.println("静态内部类测试方法");
}
}
public void show(){
InnerStaticClass innerStaticClass = new InnerStaticClass();
innerStaticClass.age="50";
innerStaticClass.play();
System.out.println(innerStaticClass.age);
}
//获取内部类对象方法
public StaticClass getStaticClass(){
return new StaticClass();
}
}
外部类访问自身静态内部类的特点:
-
静态内部类支持定义static修饰的静态成员变量和普通成员变量
-
外部类方法可以直接访问静态内部类中的任何内容,包括私有
-
内部类无法访问外部类的普通成员,但是可以访问静态成员
静态内部类的其他类访问:
public static void main(String[] args) {
//通过外部类访问内部类中的数据
MemberClass memberClass = new MemberClass();
memberClass.show();
//通过外部类的方法获取内部类的对象--私有静态内部类不可使用以下方法
MemberClass.StaticClass staticClass = memberClass.getStaticClass();
MemberClass.StaticClass staticClass1 = new MemberClass.StaticClass();
}
其他类访问静态内部类的特点
-
调用者可以通过外部类的公有方法,获取静态内部类中的数据
-
如果内部类定义为private,则无法再通过其他方式访问
-
如果内部类定义为public或default,则可以通过直接new对象,或者使用公有方法
非静态内部类
非静态内部类不通过static修饰的内部类,属于类的实例,在初始化时创建
非静态内部类实现及外部类的访问:
public class MemberClass {
//私有非静态内部类
private class InnerClass{
//非静态内部类不支持定义静态成员变量
// private static String sex;
private String hobby;
public void play(){
String str= id;
System.out.println(str+members+"非静态内部类方法");
}
}
//非私有非静态内部类
class PublicClass{
//非静态内部类不支持定义静态成员变量
// private static String sex;
private String hobby;
public void play(){
String str= id;
}
}
public void showInner(){
InnerClass innerClass = new InnerClass();
innerClass.hobby="打球";
innerClass.play();
System.out.println(innerClass.hobby);
}
}
外部类访问自身非静态内部类的特点:
-
非静态内部类不支持定义static修饰的静态成员变量
-
外部类方法可以直接访问非静态内部类中的任何内容,包括私有
-
内部类可以访问外部类的普通成员和静态成员
非静态内部类的其他类访问:
public static void main(String[] args) {
//通过外部类访问内部类中的数据
MemberClass memberClass = new MemberClass();
memberClass.showInner();
//通过外部类的方法获取内部类的对象--私有非静态内部类不可使用以下方法
MemberClass.PublicClass publicClass = memberClass.getPublicClass();
MemberClass.PublicClass publicClass1 = new MemberClass().new PublicClass();
}
其他类访问非静态内部类的特点
-
调用者可以通过外部类的公有方法,获取非静态内部类中的数据
-
如果内部类定义为private,则无法再通过其他方式访问
-
如果内部类定义为public或default,则可以通过直接new对象,或者使用公有方法
成员内部类的修饰符:
-
一般内部类是不让外界直接访问的
-
private为了保证数据的安全性
-
static为了方便访问数据
局部内部类
在局部位置(方法、代码块、构造器中)定义的类,被称为局部内部类,局部内部类不支持定义静态内部类
代码块中定义内部类
public class LocalClass {
//局部内部类
{
class InnerLocalClass{
private String name;
// private static String age;
}
}
//不支持在静态代码块中定义静态内部类
static {
// static class InnerLocalClass{
// private String name;
private static String age;
// }
}
}
代码块中内部类的特性:
-
在内部类中不支持定义静态成员变量
-
在静态内部类中也不支持定义静态局部内部类
-
局部内部类只在当前代码块有效
-
局部内部类可以直接访问外部类的成员
-
在局部位置,可以创建内部类对象,通过对象调用内部方法,来使用局部内部类功能
局部内部类一般很少有人使用,代码块和其他成员中的内部类都是相似的特性
匿名内部类
匿名内部类适合创建一次性使用的类,创建一个匿名内部类时会立即创建一个该类的实例,这个类定义后立即消失,是一次性的不支持重复使用
匿名内部类的实现1:匿名内部类继承一个普通类
public class AnonymousClass {
public void test(){
System.out.println("写入一个父类的代码");
}
}
public static void main(String[] args) {
//匿名内部类
//此时的匿名内部类可以看作是继承了AnonymousClass类的一次性类,我们可以重写一些方法来实现一次性的操作
new AnonymousClass(){
@Override
public void test(){
System.out.println("写入一个子类的代码");
}
}.test();
}
匿名内部类的实现2:匿名内部类实现一个接口
public interface AnonymousInterface {
void show();
}
public static void main(String[] args) {
//此时的匿名内部类可以看作是实现了AnonymousInterface接口的一次性实现类,我们可以实现一些方法来完成某些一次性的操作
//也可以不要=和前面的部分,这里只是想表明,可以使用接口的实例来接收匿名内部类
AnonymousInterface a=new AnonymousInterface(){
@Override
public void show() {
System.out.println("我实现了AnonymousInterface的show方法");
}
};
a.show();
}
匿名内部类的实现3:匿名内部类继承一个抽象类
public abstract class AnonymousAbstract {
public abstract void play();
}
public static void main(String[] args) {
//此时的匿名内部类可以看作是实现了AnonymousAbstract抽象类的一次性子类,我们可以实现/重写一些方法来完成某些一次性的操作
new AnonymousAbstract(){
@Override
public void play() {
System.out.println("实现抽象类中的抽象方法");
}
};
}
匿名内部类的常用用法:作为参数进行传递
public class AnonymousClass {
private String name;
private Integer price;
public String getName() {
return name;
}
public Integer getPrice() {
return price;
}
}
public class InnerTest {
public void test1(AnonymousClass anonymousClass){
System.out.println("小明买了一个"+anonymousClass.getName()+"花费"+anonymousClass.getPrice()+"元");
}
public static void main(String[] args) {
//其他实现类如下面操作,需要注意的是,如果接口/抽象类中有多个抽象方法,需要一一实现
//因此以接口的方式声明匿名内部类最优的方式是只有一个抽象方法,这也是lambda表达式的由来
InnerTest innerTest = new InnerTest();
innerTest.test1(new AnonymousClass(){
@Override
public Integer getPrice() {
return 52;
}
@Override
public String getName(){
return "影片";
}
});
}
}
输出结果:小明买了一个影片花费52元
匿名内部类的特点:
-
匿名内部类不能是抽象类[//]: # (但是可以继承抽象类),因为匿名内部类会立即创建实例,抽象类不允许创建实例,因此不允许将匿名内部类定义为抽象类
-
匿名内部类不允许定义构造器,由于匿名内部类没有类名,所以无法定义构造器,如果需要初始化可以定义初始化代码块,通过实例初始化来完成构造器所需要完成的事情
-
匿名内部类只能一次性使用,不能多次使用,一般用于输出/处理数据:例如传参,处理外部数据等
-
匿名内部类必须实现接口/抽象类中的所有抽象方法
-
匿名内部类的父类中如果存在有参构造器,则需要传递参数