前言:在日常的开发过程中,内部类其实用的并不多,所以对于内部类的认知,还是停留在比较肤浅的概念认知和代码解读,下面会做下整理,至于内部类对于程序设计的裨益,等用到的时候有了感悟,再回来做补充吧。
1.什么是内部类
简单来说:将一个类的定义放在另一个类的定义内部,这就是内部类。
public class Outter {
private void show(){
System.out.println("This is outter class");
}
class inner{
public Outter getOutterClass(){
return Outter.this;
}
}
public static void main(String [] args){
Outter out = new Outter();
Outter.inner inner = out.new inner();
inner.getOutterClass().show();
}
}
这里的inner class就是内部类
2.为什么要用内部类
内部类的好处,就目前来说,个人觉得有以下几点:
1.内部类提供了更好的封装,除了该外围类,其他类都不能访问。
2.非静态内部类自动捕获外部类的引用,所以拥有其外部类全部域和方法的访问权限。
3.可以让多个内部类以不同的方式实现或继承同一个接口。
4.可以利用向上转型,通过接口&内部类实现多重继承。
这么说起来似乎有些宽泛,很难理解,下面我们来说明下吧。
2.1内部类拥有更好的封装性
关于这一点,是因为内部类的作用域仅限于其外部类。所以对其他类而言,该内部类是不可知的。就不再做过多赘述了。
2.非静态类自动捕获外部类的引用,拥有外部类全部域和方法的访问权限。
查看生成的字节码,我们看到的红圈圈出来的就是外部类的引用。因此,内部类可以直接调用外部类的全部参数和方法。
2.3可以让多个内部类以不同的方式实现或继承同一个接口
这一点在实际应用中,可能会与第四点结合起来使用,让多个内部类实现同一个接口,然后通过向上转型,达到了多重继承的目的。且实现过程对外不可知。
注:因为是向上转型,内部类独有的方法无法调用。
public interface People {
String getPeopleName();
}
public class Outter {
public People getFriend(){ //返回实现了接口的类的对象
return new Friend();
}
private class Friend implements People{//实现接口
public String getPeopleName(){
return "people name";
}
public String getName(){ //独有的方法
return "Just want known";
}
}
}
public class Main {
public static void main(String[] args){
Outter out = new Outter();
// Outter.Friend fri = out.new Friend();//其他外部类不能调用内部类,无法通过编译期
People fri2 = out.getFriend();
System.out.print(fri2.getPeopleName());
// System.out.print(fri2.getName());//同样无法通过编译,因为是向上转型,特有方法无法调用
}
}
以上对于内部类的好处做了一个大致的描述。更具体的好处需要我们在使用过程中自行体悟了。下面还是简单补充一下内部类的相关基础知识吧。
3.内部类基础知识
3.1内部类与外部类的相互调用
当生成一个内部类对象的时候,此对象会与制造它的外围对象产生联系——它能访问其外围对象的全部成员(包括private成员)。
我们可以使用外部类的名字后面加圆点和this
public Class Outter{
private void show(){
System.out.println("This is outter class");
}
class inner{
public Outter getOutterClass{
return Outter.this;
}
}
public static void main(String [] args){
Outter out = new Outter();
out.inner inner = out.new Inner();
inner.getOutterClass().show();
}
}
3.2.成员内部类
成员内部类是内部类中相对更普遍且普通的用法,他就是写在类里面的另一个类,当某个外部类创建一个内部类的时候,该内部类会自动捕获一个指向其外部类的引用(嵌套类除外),所以它能访问其外部类的全部成员而不需要任何条件。如上面例子中,show方法是私有的。
在使用过程中有两点需要注意:
1.内部类是依赖外部类的,所以一定要先创建外部类,后创建内部类
2.成员变量中不能包含有static变量(加了static变量,存放位置就不在对象同一个内存地址中了,归属也就不属于外部类,与第一条相违背)
3.3.静态内部类(嵌套类)
关键字static除了修饰成员变量、方法、代码块之外,还可以修饰内部类,使用内部类修饰的内部类我们称之为静态内部类(或嵌套类)。需要注意一点就是,一般我们在创建内部类的时候,内部类都会自动捕获一个指向外部类的引用,而静态内部类最大的区别也就在于,它没有指向外部类的引用,这也就意味着它的创建不需要依赖外部类且不能访问外部类的非static变量、方法。
public class OutterClass{
private String str1 = "NotStatic string";
public static String str2 = "static String";
/**静态内部类**/
static class inner1{
public static String str3 = "This is static inner String";
public void in1Show(){
/*静态内部类只能访问静态变量
*不能访问非静态变量和方法*/
System.out.println("outterClass str"+str2)
}
}
/**非静态内部类**/
class inner2{
pulic void in2Show {
System.out.priintln("outterClass"+str1)
}
}
/**外部类的方法**/
public void outShow(){
System.out.println(inner1.str3); //内部类的静态变量可以在外部类直接访
new Inner1().in1Show();//静态内部类可以直接创建,无需依赖外部类
Outter.inner2 inner2= new Outter.new Inner(); //非静态内部类创建需要依赖外部类
inner2.in2Show();//使用非静态类的方法需要通过内部类调用
}
public static void main(String [] args){
Outter out = new Outter();
out.outShow();
}
}
3.4.局部内部类
上面的类都是定义在外部类中的,虽然创建调用方式略有不同,但是都可以被其他类调用,可是有些时候我们会写一个内部类来辅助处理复杂内容且不想被其他人调用,这个时候我们就可以考虑使用局部内部类——创建在方法体内的内部类,编译与成员内部类相同,但是作用域缩小到方法体内,只有该方法内可用,且生命周期随该方法结束而终结。
3.5.匿名内部类
由于构造器的名字必须与类名相同,而匿名内部类没有类名,所以匿名类不能含有构造器。取而代之的是将构造器参数传递给超类的构造器。。创建格式如下:
new 父类构造器(参数列表)|实现接口()
{
//匿名内部类的类体部分
}
在这里我们看到使用匿名内部类我们必须要继承一个父类或者实现一个接口,当然也仅能只继承一个父类或者实现一个接口。同时它也是没有class关键字,这是因为匿名内部类是直接使用new来生成一个对象的引用。当然这个引用是隐式的。
public abstract class Bird {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public abstract int fly();
}
public class Test {
public void test(Bird bird){
System.out.println(bird.getName() + "能够飞 " + bird.fly() + "米");
}
public static void main(String[] args) {
Test test = new Test();
test.test(new Bird() {
public int fly() {
return 10000;
}
public String getName() {
return "大雁";
}
});
}
}
------------------
Output:
大雁能够飞 10000米
**
一个抽象类是没有办法直接new的,必须先有实现类才能new处它的实现类实例。又由于匿名内部类不能是抽象类,所以它必须实现它的抽象父类或者接口里的抽象方法。匿名内部类其实是存在一个缺陷的——只能被使用一次,创建匿名类时会立即创建一个该类的实例,方法结束时匿名类就会被自动销毁,所以不能重复使用。
在使用匿名内部类的过程中,我们需要注意以下几点:
1.匿名内部类必须继承或实现一个接口,但是也只能继承一个类或实现一个接口。
2.匿名内部类中不能定义构造函数的。(构造需要通过代码块来实现)。
3.匿名内部类中不能存在任何静态成员变量和静态方法。
4.匿名内部类为局部内部类,所以局部内部类的所有限制同样对匿名内部类生效。
5.匿名内部类不能是抽象的,必须要实现继承的类或实现接口的抽象方法。
小结:其实关于内部类,更高级的应用据说是关于程序结构的,这方面目前还没有比较多的使用经验,所以不做评价。等用到的时候有了感悟,再回来做补充吧。