本文主要介绍了内部类的基础知识,包括成员内部类,局部内部类,匿名内部类的特点和注意事项,供初学者参考学习。水平有限,错误之处敬请留言指正。
欢迎有疑问的小伙伴留言提问哦~
把一个类定义到另一个类的内部,我们就称之为内部类;
比如把类A定义在类B的内部,我们就把类A称为内部类,把类B称为外部类;
内部类根据定义的位置不同,分为成员内部类和局部内部类。
成员内部类:内部类定义在外部类的成员位置(外部类方法外);
局部内部类:内部类定义在外部类的局部位置(外部类方法中);
class A{
class B{} //成员内部类
public void method(){
class C{} //成员外部类
}
}
1、内部类可以直接访问外部类的成员,包括私有;
2、外部类要访问内部类的成员,必须先创建对象;
如果我们要在测试类中访问内部类的成员,就必须创建内部类对象;
创建格式:外部类名.内部类名 对象名 = new 外部类名().new 内部类名();
public class Test {
public static void main(String[] args) {
//如果要在main方法里访问内部类,首先要创建内部类对象、
//创建格式:
//外部类名.内部类名 对象名 = 外部类对象.内部类对象;
Outer.Inner oi = new Outer().new Inner();
//然后我们就可以访问到内部类的成员
System.out.println("c=" + oi.c);
oi.innerShow();
}
}
class Outer {
//定义两个变量供内部类访问
int a = 100;
private int b = 1000;
//定义一个方法供内部类访问
public void outerShow() {
System.out.println("我是外部类的show方法");
}
//定义一个成员内部类
/*成员内部类的特点:
1、可以直接访问外部类的成员,包括私有成员;
2、外部类要访问内部类的成员,必须先创建对象。
*/
//这里我们没有加修饰符,方便测试,如果加上private修饰符,就把内部类保护起来了
//别的类就无法访问到这个内部类,那么为了方便数据访问,就要再加上static关键字
class Inner {
//定义一个成员变量供外部类访问
int c = 50;
public void innerShow() {
System.out.println("我是内部类的show方法");
System.out.println("成员内部类——我可以直接访问到外部类的成员变量(包括私有):" + "a=" + a + " " + "b=" + b);
}
public void innerShow1() {
System.out.println("我是内部类的show1方法");
System.out.println("成员内部类——我可以直接访问到外部类的成员方法(包括私有):");
outerShow();
}
}
//外部类如果要访问内部类的成员,得先创建对象
public void outerTest() {
Inner inner = new Inner();
System.out.println("c=" + inner.c);
inner.innerShow();
inner.innerShow1();
}
}
//注意,我们并不能通过内部类对象去访问外部类的成员
//那么我们能不能通过创建外部类对象去访问内部类成员呢?
//答案是否定的。那么我们创建内部类有什么用呢?
/*
⒈ 内部类对象可以访问创建它的对象的实现,包括私有数据;
⒉ 内部类不为同一包的其他类所见,具有很好的封装性;
⒊ 使用内部类可以很方便的编写事件驱动程序;
⒋ 匿名内部类可以方便的定义运行时回调;
5、内部类可以方便的定义
*/
1、成员内部类的修饰符:
private 为了保证数据的安全性;
static 为了方便访问数据;
注意:
静态内部类访问外部类数据必须用静态修饰;
成员方法可以是静态的,也可以是非静态的;
public class demo2 {
public static void main(String[] args) {
//外界创建静态内部类对象
/*格式:外部类名.内部类名 对象名 = new 外部类名.内部类名();*/
Outer.Inner1 inner1 = new Outer.Inner1();
//通过对象访问内部类成员变量
System.out.println("c = " + inner1.c);
//通过对象访问内部类方法
inner1.method2();
inner1.method();
}
}
class Outer {
//创建一个非静态变量和静态变量
int a = 2;
static int b = 3;
//创建一个非静态方法和静态方法
public void show() {
System.out.println("我是外部类的非静态方法");
}
public static void show2() {
System.out.println("我是外部类的静态方法");
}
//private 修饰内部类之后,外界就不能创建内部类对象了,但外部类仍然可以访问
private class Inner {
}
//外部类创建私有内部类对象
Inner inner = new Inner();
//static 修饰内部类之后,外界创建内部类对象的方式就要改变
/*格式: 外部类名.内部类名 对象名 = new 外部类名.内部类名();*/
//不加static 修饰创建内部类对象的格式:
/*格式: 外部类名.内部类名 对象名 = new 外部类名().new 内部类名();*/
static class Inner1 {
/*注意事项:
a:静态内部类访问的外部类数据必须用静态修饰。
b: 成员方法可以是静态的也可以是非静态的*/
int c = 4;
//内部类静态方法
static void method() {
}
//内部类非静态方法
static void method2() {
System.out.println("静态内部类只能访问到外部类的静态成员:" + "b=" + b);
//访问外部类的静态方法
show2();
}
}
}
来看一道简单的成员内部类的习题:
要求:使用已知的变量,在控制台输出30,20,10。
class Outer {
public int num = 10;
class Inner {
public int num = 20;
public void show() {
int num = 30;
System.out.println(?);
System.out.println(??);
System.out.println(???);
}
}
}
class InnerClassTest {
public static void main(String[] args) {
Outer.Inner oi = new Outer().new Inner();
oi.show();
}
}
答案
System.out.println(num); //30
System.out.println(this.num); //20
System.out.println(Outer.this.num); //10
1、可以直接访问外部类的成员
2、可以创建外部类对象,通过对象调用内部类方法,来使用局部内部类功能
3、局部内部类访问局部变量必须用final修饰
为什么呢?因为局部变量会随着方法的调用完毕而消失,这个时候,局部对象并没有马上从堆内存中消失,还要使用哪个变量。为了让数据还能据需被使用,就用final修饰,这样,在堆内存里面存储的其实是一个常量值。
public class Test {
public static void main(String[] args) {
//局部内部类外界是无法创建对象的
Outer outer = new Outer();
outer.show();
}
}
class Outer {
int a = 10;
private int b = 20;
public void show2() {
}
public void show() {
//定义一个局部变量
final int c = 30;
//JDK1.7之前不加final会报错,但是在JDK1.8之后不会报错
//局部内部类
class Inner {
//局部内部类可以直接访问外部类的成员
public void method() {
System.out.println(a);
System.out.println(b);
show2();
}
}
//可以创建内部类对象来访问内部类成员
Inner inner = new Inner();
inner.method();
}
}
就是局部内部类的简化写法。
前提:存在一个类或者接口,这里的类可以是具体类也可以是抽象类
格式:
new 类名或者接口名(){
重写方法;
}
本质:
是一个继承了该类或者实现了该接口的子类匿名对象。
匿名类案例演示——抽象类
public abstract class Father{
public abstract void show();
}
public class Son extends Father{
@Override
public void show() {
System.out.println("我重写了父类中的show方法");
}
}
public class MyTest {
//匿名内部类:就是局部内部类的简写方式
public static void main(String[] args) {
//匿名内部类
new Father() {
@Override
public void show() {
System.out.println("1111111");
}
}.show();//调用show方法
//通过setFather方法重写show方法并且调用show方法
setFather(new Father() {
@Override
public void show() {
System.out.println("2222222");
}
});
//匿名内部类的本质就是一个对象,是继承了抽象类或者实现了该接口的子类对象
Son son = new Son();
setFather(son);
}
//我们可以专门写一个方法来完成这一过程
public static void setFather(Father father) {
father.show();
}
}
匿名类案例演示——接口
public interface Interface {
//接口中变量的默认修饰符是public static final
//接口中方法的默认修饰符是public abstract
public abstract void show();
}
public class MyImplements implements Interface {
@Override
public void show() {
System.out.println("我重写了接口中的show方法——11111111");
}
}
public class Test {
public static void main(String[] args) {
//创建一个myImplemerts类的新对象,并调用show方法
MyImplements myImplements = new MyImplements();
myImplements.show();
//匿名内部类的本质就是一个实现了接口或者继承了抽象类的子类对象
//我们分开写可能方便理解,匿名内部类就是一个对象
Interface anInterface = new Interface() {
@Override
public void show() {
System.out.println("我重写了接口中的show方法——2222222");
}
};
anInterface.show();
/*
* 我们发现,匿名内部类在这里的作用和 MyImplements类对象myImplements的作用是一样的
* 再次证实了:匿名内部类就是一个实现了接口的子类对象*/
setInterface(new Interface() {
@Override
public void show() {
System.out.println("我重写了接口的show方法——333333333");
}
});
}
public static void setInterface(Interface i) {
i.show();
}
}
输出:
我重写了接口中的show方法——11111111
我重写了接口中的show方法——2222222
我重写了接口的show方法——333333333
首先回顾我们曾经见过的方法的形式参数是引用类型的情况,我们知道这里需要一个子类对象。而匿名内部类就是一个子类匿名对象,所以我们可以借此改进以前的做法。
abstract class Person {
public abstract void show();
}
class PersonDemo {
public void method(Person p) {
p.show();
}
}
class PersonTest {
public static void main(String[] args) {
//如何调用PersonDemo中的method方法呢?
//使用匿名内部类就可以
new PersonDemo().method(new Person(){
@Override
public void show(){
System.out.println("调用成功");
}
});
}
}
习题
按照要求,补齐代码
interface Inter { void show(); }
class Outer { //补齐代码 }
class OuterDemo {
public static void main(String[] args) {
Outer.method().show();
}
}
要求在控制台输出”HelloWorld”
答案
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();
}
}
A: 举例: 电脑类中的内存条接口
B: 定义电脑类,然后在电脑类中定义内存条接口
方案一:
public class InnerInterfaceDemo {
public static void main(String[] args) {
//创建成员内部类对象
Computer.MemoryImp cm = new Computer().new MemoryImp();
//调用方法
cm.showMemory("32G");
}
}
//电脑类
class Computer {
//电脑类中的内存条接口——私有化以保护数据
private interface Memory {
//添加一个抽象方法以提供数据
public abstract void showMemory(String mermory);
}
//成员内部类
class MemoryImp implements Computer.Memory {
@Override
public void showMemory(String mermory) {
System.out.println("内存为" + mermory);
}
}
}
方案二:
public class InnerInterfaceDemo {
public static void main(String[] args) {
//创建Computer对象
Computer computer = new Computer();
//调用appMemory()方法
computer.appMemory("32G");
}
}
//电脑类
class Computer{
//电脑类中的内存条接口——私有化以保护数据
private interface Memory{
//添加一个抽象方法以提供数据
public abstract void showMemory(String mermory);
}
//我们写一个方法供外界访问内存条
public void appMemory(String mermory){
//匿名内部类
new Memory(){
@Override
public void showMemory(String mermory) {
System.out.println("内存为"+mermory);
}
}.showMemory(mermory);
}
}