[java核心篇02]__内部类

  • 前言

    其实我们在前面已经初步接触到内部类了,但是我们去对它的作用并不胜了解.只是简单的知道了类的定义也是可以嵌套的,定义在一个类里面的类就是内部类.
class out{
private String name;
private int age;
class in{
private String sex;
}
public String getName(){
return this.name;
}
}

但是关于内部类有什么作用,有什么分类都不是很了解,通过这篇文章来对java内部类的学习进行加深.


  • 内部类的特点

1、内部类可以用多个实例,每个实例都有自己的状态信息,并且与其他外围对象的信息相互独立。

2、在单个外围类中,可以让多个内部类以不同的方式实现同一个接口,或者继承同一个类。

3、创建内部类对象的时刻并不依赖于外围类对象的创建。

4、内部类并没有令人迷惑的“is-a”关系,他就是一个独立的实体。

5、内部类提供了更好的封装,除了该外围类,其他类都不能访问。

6、内部类可以访问包括私有成员在内的外部类的所有成员。

  • 内部类的作用

    书上的描述并不详细,于是google了下相关的文章,感觉还是说法不一, 具体的作用有很多,于是大致总结两点:
    • 内部类并不象外部类一样,它可以使用provate,proteced,这意味着它可以更好的封装,更好的隐藏起来,在我们需要隐藏某些方法的实现细节时,可以使用到内部类.而外部类则不行.

    • 另外一个作用就是能够更好的解决java多继承的问题,我们知道,在java语言中秉性的是单继承,而内部类与外部类的继承关系是互不干扰的,我们在前面知道了,java类可以通过接口的多继承解决多继承的问题,但那并没有彻底解决这个问题,而通过内部类则可以彻底解决这个问题,我们可以通过内部类实现类的多继承(可以定义多个内部类继承多个抽象类或具体类)


  • 内部类的分类

    • 静态内部类与非静态内部类

      内部类更具其定义方法分为静态内部类和非静态内部类.其区别:
      • 静态内部类可以有静态成员变量,而非静态内部类则不能有静态成员变量。
      • 静态内部类可以访问外部类的静态变量,但不可访问外部类的非静态变量;
      • 非静态内部类的非静态成员方法可以访问外部类的非静态变量,也可以访问静态变量。
      • 静态内部类的创建不依赖于外部类,而非静态内部类必须依赖于外部类的创建而创建。

我们通过一个例子看看:

public class sty_internalClass {
public static void main(String[] args) {
// 创建内部类实例化对象的第一种方式..
textclass text = new textclass(); // 实例化外部类对象
textclass.internaltextclass internaltextclass = text.new internaltextclass(); // 实例化内部类的对象要通过外部类对象来实现.
// 创建内部类的实例化对象的第二种方式
textclass.internaltextclass internaltextclass1 = new textclass().new internaltextclass();
// 创建静态内部类实例化对象
textclass.astaticinclass astaticinclass = new textclass.astaticinclass(); // 静态内部类的实例化不需要依赖外部类.
}
} class textclass{
private String name;
static private int age; public class internaltextclass{ // 内部类
String sex="男";
internaltextclass(){ // 构造方法
name = "小舍";
age = 23;
}
void input(){
System.out.println("这是内部类的一个方法");
System.out.println(age);
}
}
public static class astaticinclass{
void funtion(){
System.out.println(age);
}
} public internaltextclass getinternaltextclass(){
return new internaltextclass();
} void ainput(){ // 外部类的一个方法,调用内部类的属性和方法.
internaltextclass internaltextclass = new internaltextclass();
internaltextclass.sex = "男";
} }

我们可以观察出:非静态内部类的实例化必须依赖外部类(需要通过一个外部类的实例化对象创建对象)

而静态内部类是不依赖外部类的(可以直接创建实例化对象)


  • 非静态内部类:

    • 成员内部类
    • 方法(局部)内部类
    • 匿名内部类
  • 成员内部类

就其文字含义而言,它就是作为一个类的成员存在的内部类.我们可以将它看做一个类的一个成员,只不过这个成员的类型是一个类而已.

 class textclass{
private String name;
static private int age;
public class internaltextclass{ // 内部类
String sex="男";
internaltextclass(){ // 构造方法
name = "小舍";
age = 23;
}
void input(){
System.out.println("这是内部类的一个方法");
ainput(); // 可以没有任何限制的调用外部类的方法.
}
}
void ainput(){ // 外部类的一个方法,调用内部类的属性和方法.
internaltextclass internaltextclass = new internaltextclass();
internaltextclass.sex = "男";
}
}

我们甚至可以通过定义get方法来获得一个成员内部类的对象.

    public internaltextclass getinternaltextclass(){
return new internaltextclass();
}

我们可以观察到:

  • 成员内部类的定义是更成员变量并列的,所以可以看成是外部类的一个成员.
  • 成员内部类的好处就是可以没有任何限制的访问外部类的属性和方法.不管是静态还是非静态.
  • 用内部类定义在外部类中不可访问的属性。这样就在外部类中实现了比外部类的private还要小的访问权限,更好的封装隐藏性。

    (成员内部类不能有静态成员变量和方法,这是因为成员内部类不能被定义为静态的,定义为静态就成了静态内部类了,而之所以静态内部类不叫静态成员内部类,这应该是因为静态内部类对象的创建不依赖于外部类,所以严格来说算不上是外部类的一个成员.)

  • 方法(局部)内部类

    很多文章都喜欢将它称为局部内部类,但是我觉得这样并不贴切,很模糊概念.其实局部内部类就是定义在一个方法体中的内部类.它与局部变量类似,其作用范围也只有方法体大小,其访问权限也只有方法体大小,这里我们就可以察觉到,那么局部内部类真的是太适合封装了,其隐蔽性更加高了.

我们放大上面例子中的ainput方法(外部类的普通方法),在里面加入一个局部内部类:

   void ainput(){  // 外部类的一个方法,调用内部类的属性和方法.
final String[] a = new String[0];
internaltextclass internaltextclass = new internaltextclass(); // 通过实例化内部类来调用内部类的成员变量.
internaltextclass.sex = "男";
// 定义局部内部类
class Localinclass{ void Local(){
a[0] = "外部方法体中的变量";
System.out.println("局部内部类中的方法");
System.out.println(a[0]);
}
}
//在方法体中调用局部内部类.
Localinclass localinclass = new Localinclass();
localinclass.Local();
}

我们可以观察到,在方法体中的内部类,只能从上往下运行(调用只能再内部类的下面,否则无法识别到,这应该是是因为java运行的机制,在方法体中是从上到下的.)

另外,在局部内部类中,我们只能访问到方法体中的final型变量.


  • 匿名内部类

    匿名内部类比较特殊,它的创建不需要类名(当然也不需要class关键字),但其必须继承一个抽象类或是一个接口(只能是一个).

匿名内部类的定义是这样的:

new 父类构造器(参数){  // new一个父类的引用
类体部分
}
new 接口(){
类体部分
}

匿名内部类实际完成的工作其实就是实现抽象类或接口中的方法.然后作为一个实例的对象被创建.

我们来看一个例子.

package java02.day_4_14;

/**
* @outhor xiaoshe
* @date 2019/4/15 - @time 1:55
* 匿名内部类
*/
public class sty_anonymous {
public void outman(man m){
System.out.println(m.toout());
}
public static void main(String[] args) {
sty_anonymous styAnonymous = new sty_anonymous();
// 匿名内部类的使用
styAnonymous.outman(new man() {
@Override
String sex() {
return "男";
}
@Override
String name() {
return "男人";
}
@Override
String toout() {
return(this.name()+"\n"+this.sex());
}
});
}
}
// 定义一个抽象类
abstract class man{
private String name;
private String sex;
abstract String sex(); // 定义一个抽象方法
abstract String name(); // 定义一个抽象方法
abstract String toout();
}

我们可以看出,匿名内部类在这里的功能是实现抽象类中的抽象方法,应为抽象类是不能直接实例化的,所以这里通过了匿名内部类继承了抽象类man,而这里的new man{...}就是整个匿名内部类,它在这里不是作为方法outman(man m)中的man类实例对象m二存在的(因为抽象类不能直接实例化对象), 而是作为一个继承了抽象类man的匿名内部类(即new man{...})的实例化对象而存在的.同时抽象类被继承后其抽象方法必须全部实现.

我们将整个匿名内部类收起来:

[java核心篇02]__内部类

同时我们应该注意到,匿名内部类的使用范围是十分有限的,一个匿名内部类只能被使用一次(只在一个方法中当做一个实例化对象来使用)


ps:发现昨天核心以的关于抽象类和接口的知识点有很大差错,这次记住教训,学东西不能图快,切勿没完全整明白就跳过.明天重新总结,

检讨之


更新时间:

2019-4-15

2:30

上一篇:MyBatis源码解读(3)——MapperMethod


下一篇:Mybatis源码解读-设计模式总结