一.概述
将类写在其他类的内部,也可以写在其他类的成员位置和局部位置,这种类就被称为内部类,其他类也被称为外部类
在描述事物时,若一个事物内部还包含其他的事物,例如汽车中的发动机,就可以用内部类来描述
class 汽车{
class 发动机{
}
}
二.内部类的特点
内部类提供了更好的封装,只有外部类可以访问内部类
内部类可以独立继承一个接口,不受外部类是否继承接口的影响
内部类可以直接访问外部类的成员,包括私有private
外部类想要访问内部类的成员,必须创建对象
在外部类中,即使内部类中用private修饰的成员,也可以在外部类中以内部类对象.成员的方式访问
private修饰内部类,则外部类以外不能访问,只能在外部类访问
三.内部类的分类
内部类分为成员内部类与局部内部类
其次还有匿名内部类和静态内部类
定义内部类时,就是一个正常定义类的过程,包含各种修饰符、继承、实现关系等
四.成员内部类
1.定义
定义在外部类中的成员位置。与类中的成员变量相似,可通过外部类.对象进行访问
访问方式:外部类名.内部类名 变量名=new 外部类名().new 内部类名()
class Body{
private boolean life=true;
public class Heart{
public void jump(){
System.out.println("心脏扑通扑通跳");
System.out.println("生命状态"+life);
}
}
}
public static void main(String[] args){
Body.Heart bh=new Body().new Heart();
bh.jump();
}
3.成员内部类的同名变量调用:
public class Outer{
int i=1;
class Inner{
int i=2;
public void inner(){
int i=3;
System.out.println(Outer.this.i);
}
}
}
五.局部内部类
1.概述
局部内部类,定义在外部类方法中的局部位置。与访问方法中的局部变量相似,可以调用方法进行访问
可以直接访问外部类成员
局部内部类,只能在方法体中使用
局部类不能加访问修饰符,因为他们不是类成员
访问方式:在外部类方法中,创建内部类对象进行访问
2.例子
class Party{
public void PuffBall(){
class Ball{
public void puff(){
System.out.println("气球膨胀了");
}
}
new.Ball().puff();
}
}
public static void main(String[] args){
Party p=new Party();
p.PuffBall();
}
3.局部内部类访问局部变量的注意事项:
局部内部类访问局部变量必须用final修饰
jdk8或者更高版本,不要求被局部内部类所访问的局部变量一定要加final
但是编译器会自动给局部变量加上final
加final的原因:
因为局部变量会随着方法的调用和结束而存亡
而局部对象并没有立刻从堆内存中消失,还需要使用该变量,使用final修饰后,在堆内存中存储的实际上是一个常量值。
六.匿名内部类
1.概述
就是一个没有名字的局部内部类
匿名内部类是创建某个类型子类对象的快捷方式
定义一个内部类(成员内部类,局部内部类)没有名字,意味着类不能通过名字来复用,只能在类定义的时候被使用一次
2.特点
匿名内部类没有修饰符
匿名内部类必须继承一个类或者实现一个接口
这里的类可以是具体类也可以是抽象类
匿名内部类中不能存在任何静态成员或方法
匿名内部类没有构造方法,因为没有类名
匿名内部类为局部内部类,所以局部内部类的所有限制同样生效
匿名内部类不能是抽象的,必须实现继承的类或接口的所有抽象方法
3.格式:
new 父类或接口(){
//进行方法重写
};
4.匿名内部类如果不定义变量引用,则就是匿名对象
pubic abstract class Person{
public abstract void eat();
}
new Person(){
public void eat(){
System.out.println("我吃了");
}
}.eat();
5.匿名内部类的使用:
一般使用匿名内部类的场景是,要继承或实现的接口只有一个抽象方法,比如添加一个监听器:
public class Button{
public void click(){
//匿名内部类,实现的是ActionListener接口
new ActionListener(){
public void onAction(){
System.out.println("click action...");
}
}.onAction();
}
//匿名内部类必须继承或实现一个已有的接口
public interface ActionListener{
public void onAction();
}
public static void main(String[] args){
Button button=new Button();
button.click();
}
}
其次,当方法的形式参数是一个接口时,在该方法传递实际参数时,实际传递的是一个接口的子类对象。
传递的这个实际参数,就可以用匿名内部类来代替
public class AnoyInnerDemo2{
public static void main(String[] args){
//1.利用常规方式调用input方法
//A a=new A();
//input(new A());
//2.利用匿名内部类
input(new Ordinary(){
public void toDo(){
System.out.println("inner class todo");
}
});
}
//接收接口类型形式参数的方法
public static void input(Ordinary o){
o.toDo();
}
}
//接口
interface Ordinary{
void toDo();
}
class A implements Ordinary{
public void toDo(){
System.out.println("class A todo");
}
}
七、静态内部类
1. 概述
- 使用
static
修饰的 成员内部类 我们称之为静态内部类 - 静态内部类的创建是不需要依赖于外部类,可以直接创建
2. 访问特征:
- 对于 静态内部类 而言,它不能访问外部类中 非静态的 成员变量和成员方法
- 在 外部类中 访问,静态内部类,和访问普通成员内部类没有任何区别
- 在 外部类的外部 访问静态内部类,由于静态内部类,不依赖于外部类对象 :
new 外部类类名.内部类类名()
3. 例子:
public class OuterClass {
private static String outerName;
public int age;
static class InnerClass1{
/* 在静态内部类中可以存在静态成员 */
public static String _innerName = "static variable";
public void display(){
/*
* 静态内部类只能访问外部类的静态成员变量和方法
* 不能访问外部类的非静态成员变量和方法
*/
System.out.println("OutClass name :" + outerName);
}
}
class InnerClass2{
/* 非静态内部类中不能存在静态成员 */
public String _innerName = "no static variable";
/* 非静态内部类中可以调用外部类的任何成员,不管是静态的还是非静态的 */
public void display(){
System.out.println("OuterClass name:" + outerName);
System.out.println("OuterClass age:" + age);
}
}
public void display(){
/* 外部类能直接访问静态内部类静态元素 */
System.out.println(InnerClass1._innerName);
/* 静态内部类可以直接创建实例不需要依赖于外部类 */
new InnerClass1().display();
/* 非静态内部的创建需要依赖于外部类 */
OuterClass.InnerClass2 inner2 = new OuterClass().new InnerClass2();
/* 非静态内部类的成员需要使用非静态内部类的实例访问 */
System.out.println(inner2._innerName);
inner2.display();
}
public static void main(String[] args) {
OuterClass outer = new OuterClass();
outer.display();
}
}