阿里云【名师课堂】Java面向对象开发51 ~ 53:内部类的定义及使用
对于内部类的定义和使用暂时不作为我们的首要类设计原则。
51:内部类基本概念
概念
所谓的内部类指的就是在一个类中声明另一个类,被声明的类就是内部类,包含内部类的类称为内部类的外嵌类(外部类)。
理论上是可以在类中无限生命内部类,但是这样逻辑混乱操作复杂,所以基本上只声明一个内部类。
- 外嵌类的成员变量在内部类中仍然有效,即内部类可以调用外嵌类中的属性和方法;
- 内部类中不可以声明类变量和类方法,在外嵌类的类体中可以用内部类声明对象作为外嵌类的成员。
- 范例:观察一个内部类
class OuterClass{ // 定义一个外嵌类
private String msg = "Hello World!" ; // 定义外嵌类的一个属性
class InnerClass{ // 定义一个内部类
public void print(){ // 定义一个普通方法
System.out.println(msg) ; // 引用外嵌类的变量
}
}
// 在外嵌类中定义一个方法,这个方法负责产生内部类对象并且调用print()方法
public void metd(){
InnerClass in = new InnerClass() ; // 内部类实例化一个内部类对象
in.print() ; // 内部类中提供的print()方法
}
}
public class InnerDemo {
public static void main(String args[]) {
OuterClass out = new OuterClass() ; // 实例化一个外嵌类对象
out.metd() ; // 调用了一个外嵌类中的方法
}
}
代码虽然可以实现功能,但是可以看出程序的结构有些混乱。虽然内部类破坏了程序的结构,但是好处在于:
- 外嵌类的私有访问:内部类只供它的外嵌类使用。
范例:将上述程序内部类挪到外部,实现相同功能,分析:
InnerClass
和OuterClass
是两个类,并且InnerClass
需要访问到OuterClass
中的msg
属性,但是msg
使用了private封装,外部访问它必须先在OuterClass
中定义一个getter
方法。- 在
InnerClass
中的print()
方法如果想要访问msg
的内容,那么只能通过getMsg()
方法来完成,而使用getMsg()
方法必须要先使用OuterClass
实例化一个对象,那么这个时候需要把在主方法中实例化的Outer
对象传递到Inner
中。
class OuterClass{
private String msg = "Hello World!" ;
public String getMsg(){
return this.msg ;
}
public void metd(){ // 3、Outer来调用metd方法
InnerClass in = new InnerClass(this) ; // 4、this表示当前,这里是当前正在调用metd的对象
in.print() ; // 7、调用方法
}
}
class InnerClass{
private OuterClass out ;
public InnerClass(OuterClass out){ // 5、InnerClass.out = main.out
this.out = out ; // 6、引用传递
}
public void print(){ // 8、执行此方法
System.out.println(this.out.getMsg()) ;
}
}
public class InnerDemo {
public static void main(String args[]) {
OuterClass out = new OuterClass() ; // 1、实例化一个Outer对象
out.metd() ; // 2、调用OuterClass中的metd方法
}
}
实际上折腾这么久就是为了访问外部类中的私有属性(u1s1这过程太恶心了 ),没必要掌握。
具体使用
对于内部类的实际使用有以下几点:
1、通过以上代码可以发现,当前的内部类的访问必须通过外部类的方法才可以完成(比如第一段程序中,通过metd()
方法访问InnerClass
)。如果现在不想通过外部类方法进行调用,而是想在程序外部调用,就必须按照如下的形式进行内部类的实例化对象创建:
外嵌类.内部类 内部类对象 = new 外部类().new 内部类() ;
class OuterClass{ // 定义一个外嵌类
private String msg = "Hello World!" ; // 定义外嵌类的一个属性
class InnerClass{ // 定义一个内部类
public void print(){ // 定义一个普通方法
System.out.println(msg) ; // 引用外嵌类的变量
}
}
}
public class InnerDemo {
public static void main(String args[]) {
// 声明内部类对象
OuterClass.InnerClass in = new OuterClass().new InnerClass() ;
in.print() ;
}
}
注意这里的两个new:第一个是先在外嵌类实例化,第二个才是内部类的。
- 之所以要先在外嵌类中进行实例化,主要问题在于此时外嵌类中存在有属性,这些属性只有在开辟实例化对象之后才能被访问。
2、如果现在一个内部类只想被外嵌类使用,即:不希望直接产生内部类的实例化对象,那么可以用private
定义这个内部类。
class OuterClass{ // 定义一个外嵌类
private String msg = "Hello World!" ; // 定义外嵌类的一个属性
private class InnerClass{ // 定义一个内部类,只能被外嵌类使用
public void print(){ // 定义一个普通方法
System.out.println(msg) ; // 引用外嵌类的变量
}
}
public void metd(){
InnerClass in = new InnerClass() ; // 内部类实例化一个内部类对象
in.print() ; // 内部类中提供的print()方法
}
}
public class InnerDemo {
public static void main(String args[]) {
new OuterClass().metd() ;
}
}
3、在进行属性访问时都需要习惯性的加上this
,而如果想要在内部类中明确的使用this,那么语法为:外部类.this.属性
,这代表在外嵌类中的当前的属性。如果只用this
的话代表的是内部类中的属性。
52:static定义内部类
内部类定义时如果使用了static,代表这是一个外部类
(功能上、结构上),这个外部类的名称为:外部类.内部类
,同时该内部类只允许访问外部类中的static操作。语法:
外嵌类.内部类 内部类对象 = new 外部类.内部类() ;
与程序外部实例化内部类对象做对比:
外嵌类.内部类 内部类对象 = new 外部类().new 内部类() ;
范例:使用static定义内部类
class OuterClass{ // 定义一个外嵌类
private static String msg = "Hello World!" ; // msg如果是非static的外部类属性时无法被引用
static class InnerClass{ // 定义一个 static内部类 = 外部类
public void print(){
// 此时只能使用外部类中的static操作
System.out.println(msg) ; // msg是非static的外部类属性
}
}
public void metd(){
InnerClass in = new InnerClass() ; // 内部类实例化一个内部类对象
in.print() ; // 内部类中提供的print()方法
}
}
public class InnerDemo {
public static void main(String args[]) {
OuterClass.InnerClass in = new OuterClass.InnerClass() ;
in.print() ;
}
}
53:在方法中定义内部类
理论上内部类可以定义在类中的任意位置上,这就包括:类中、方法中、代码块中。不过如果从实用的角度来讲,在方法中定义内部类的形式是最常见的。
范例:在方法中定义内部类
class OuterClass{
private static String msg = "Hello World!" ;
public void metd(int num){
class InnerClass{
public void print(){
System.out.println("num = " + num) ; // 内部类访问方法的参数num
System.out.println("msg = " + msg) ;
}
}
InnerClass in = new InnerClass() ;
in.print() ;
}
}
public class InnerDemo {
public static void main(String args[]) {
new OuterClass().metd(100) ;
}
}
这段程序在JDK1.8之后是正确的,而在JDK1.8之前如果要想起到同样效果,需要给方法的参数加上final定义:第四行改为public void metd(final int num){
。
再次强调:内部类的使用暂时不该成为你的首选,但是至少应该知道内部类具备的特点:
- 破坏了程序的结构;
- 方便的进行私有属性的访问。
- 以后如果发现类名称之前还有
.
,应该立即想到是内部类的概念。