把类定义在其他类的内部,这个类就被称为内部类。
内部类的访问特点:
1、内部类可以直接访问外部类的成员,包括私有。
2、外部类要访问内部类的成员,必须创建对象。
按照内部类在类中定义的位置不同,可以分为:
1、成员位置(成员内部类)
2、局部位置(局部内部类)
成员位置的内部类
package org.danni.Demo1;
class Outer{
private int num = 10;
//成员内部类
class Inner{
public void show(){
System.out.println(num);
}
}
}
public class InnerClassDemo {
public static void main(String[] args) {
//外部类名.内部类名 对象名 = 外部类对象.内部类对象
//因为是成员位置,所以要先创造Outer对象,然后在访问里面的Inner,要访问Inner里面的方法,所以要创建Inner对象
Outer.Inner io = new Outer().new Inner();
io.show(); //10
}
}
成员内部的常见修饰符:
1、private 为了保证数据的安全性
2、static 为了让数据访问更方便
静态内部类访问的外部类数据必须用静态修饰
内部类被静态修饰后的方法:有静态方法和非静态方法
成员内部类被静态修饰后的访问格式:外部类名.内部类名 对象名 = new 外部类名.内部类名();
package org.danni.Demo1;
class Out{
private int num = 10;
private static int num2 = 100;
//静态内部类访问外部类数据必须用静态修饰
public static class In{
public void show(){
//System.out.println(num);
System.out.println(num2);
}
public static void show2(){
//System.out.println(num);
System.out.println(num2);
}
}
}
public class InnerClassDemo2 {
public static void main(String[] args) {
//成员内部类被静态修饰后的访问方式
//格式:外部类名.内部类名 对象名 = new 外部类名.内部类名();
Out.In oi = new Out.In();
oi.show(); //100
oi.show2(); //100
Out.In.show2(); //100
}
}
局部位置的内部类
1、可以直接访问外部类的成员
2、在局部位置,可以创建内部类对象,通过对象调用内部类方法,来使用局部内部类功能。
package org.danni.Demo2;
class Outer{
private int num = 10;
public void method(){
class Inner{
public void show(){
System.out.println(num);
}
}
Inner i = new Inner();
i.show();
}
}
public class Test {
public static void main(String[] args) {
Outer o = new Outer();
o.method(); //10
}
}
局部内部类访问局部变量必须用final修饰。
因为局部变量会随着方法的调用完毕而消失,但是这个时候,局部对象并没有立马从堆内存中消失,还要使用那个变量。为了让数据还能继续被使用,就用fianl修饰。加了final修饰后,这个变量就变成了常量。既然是常量,你消失了,我在内存中存储的还是那个数据,还是有数据在使用。final存储在堆内存中,堆内存的内容不会立即消失,只有垃圾回收机制回收的时候才会消失。
package org.danni.Demo2;
class Outer{
private int num = 10;
//局部内部类访问局部变量必须用final修饰
public void method(){
final int num2 = 20;
class Inner{
public void show(){
System.out.println(num);
System.out.println(num2);
}
}
//被垃圾回收机制回收的时候对象才消失。所以还会要用到num2变量。
//要还能够使用,使用final类型,存储在堆内存中,只有垃圾回收机制回首才消失。这样就可以了。
Inner i = new Inner();
i.show();
}
}
public class Test {
public static void main(String[] args) {
Outer o = new Outer();
o.method(); //10 20
}
}
匿名内部类
1、内部类的简化写法。
2、前提:存在一个类或者接口。这里的类可以是具体类也可以是抽象类。
3、格式:new 类名或者接口名( ) { 重写方法; }
4、本质:是一个 继承了类或者实现了接口的 子类匿名对象
package org.danni.Demo2;
interface Inner{
public abstract void show();
}
class Outer{
public void method(){
new Inner(){
public void show(){
System.out.println("show");
}
}.show();
//new只是声明了一个匿名类对象,他是个对象,需要继续调用才会有结果。
}
}
public class TestDemo {
public static void main(String[] args) {
Outer o = new Outer();
o.method(); //show
}
}
当是如果接口中有很多个方法要实现的时候,就很麻烦了,如下。(有改进方法)
package org.danni.Demo2;
interface Inner{
public abstract void show();
public abstract void show2();
}
class Outer{
public void method(){
new Inner(){
public void show(){
System.out.println("show");
}
public void show2() {
System.out.println("show2");
}
}.show();
new Inner(){
public void show(){
System.out.println("show");
}
public void show2() {
System.out.println("show2");
}
}.show2();
}
}
public class TestDemo {
public static void main(String[] args) {
Outer o = new Outer();
o.method(); //show show2
}
}
改进方法:
package org.danni.Demo2;
interface Inner{
public abstract void show();
public abstract void show2();
}
class Outer{
public void method(){
//多态(父接口 = 子类对象)
Inner i = new Inner(){
public void show(){
System.out.println("show");
}
public void show2() {
System.out.println("show2");
}
};
i.show();
i.show2();
}
}
public class TestDemo {
public static void main(String[] args) {
Outer o = new Outer();
o.method(); //show show2
}
}
package org.danni.Demo3;
interface Person{
public abstract void study();
}
class PersonDemo{
public void method(Person p){
p.study();
}
}
public class Test {
public static void main(String[] args) {
PersonDemo pd = new PersonDemo();
pd.method(new Person(){
public void study(){
System.out.println("study");
}
});
}
}
匿名内部类好处:用完之后就是垃圾,可以立马被回收,栈内存中没有东西指向它。