java中内部类的积累

放在一个类的内部的类我们就叫内部类。

二、 作用

1.内部类可以很好的实现隐藏

一般的非内部类,是不允许有 private 与protected权限的,但内部类可以

2.内部类拥有外围类的所有元素的访问权限

3.可是实现多重继承

4.可以避免修改接口而实现同一个类中两种同名方法的调用。

提起Java内部类(Inner Class)可能很多人不太熟悉,实际上类似的概念在C++里也有,那就是嵌套类(Nested Class),关于这两者的区别与联系,在下文中会有对比。内部类从表面上看,
就是在类中又定义了一个类(下文会看到,内部类可以在很多地方定义),而实际上并没有那么简单,乍看上去内部类似乎有些多余,它的用处对于初学者来说可能并不是那么显著,
但是随着对它的深入了解,你会发现Java的设计者在内部类身上的确是用心良苦。学会使用内部类,是掌握Java高级编程的一部分,它可以让你更优雅地设计你的程序结构。
下面从以下几个方面来介绍:
第一次见面

[java] view plain copy

  1. public interface Contents {
  2. int value();
  3. }
  4. public interface Destination {
  5. String readLabel();
  6. }
  7. public class Goods {
  8. private class Content implements Contents {
  9. private int i = 11;
  10. public int value() {
  11. return i;
  12. }
  13. }
  14. protected class GDestination implements Destination {
  15. private String label;
  16. private GDestination(String whereTo) {
  17. label = whereTo;
  18. }
  19. public String readLabel() {
  20. return label;
  21. }
  22. }
  23. public Destination dest(String s) {
  24. return new GDestination(s);
  25. }
  26. public Contents cont() {
  27. return new Content();
  28. }
  29. }
  30. class TestGoods {
  31. public static void main(String[] args) {
  32. Goods p = new Goods();
  33. Contents c = p.cont();
  34. Destination d = p.dest("Beijing");
  35. }
  36. }

在这个例子里类Content和GDestination被定义在了类Goods内部,并且分别有着protected和private修饰符来控制访问级别。Content代表着Goods的内容,而GDestination代表着Goods的目的地。它们分别实现了两个接口Content和Destination。在后面的main方法里,直接用 Contents c和Destination d进行操作,你甚至连这两个内部类的名字都没有看见!这样,内部类的第一个好处就体现出来了 隐藏你不想让别人知道的操作,也即封装性。同时,我们也发现了在外部类作用范围之外得到内部类对象的第一个方法,那就是利用其外部类的方法创建并返回。
上例中的cont()和dest()方法就是这么做的。那么还有没有别的方法呢?当然有,其语法格式如下:

[java] view plain copy

  1. outerObject=new outerClass(Constructor Parameters);
  2. outerClass.innerClass innerObject=outerObject.new InnerClass(Constructor Parameters);

注意在创建非静态内部类对象时,一定要先创建起相应的外部类对象。至于原因,也就引出了我们下一个话题 非静态内部类对象有着指向其外部类对象的引用,对刚才的例子稍作修改:

[java] view plain copy

  1. public class Goods {
  2. private valueRate = 2;
  3. private class Content implements Contents {
  4. private int i = 11 * valueRate;
  5. public int value() {
  6. return i;
  7. }
  8. }
  9. protected class GDestination implements Destination {
  10. private String label;
  11. private GDestination(String whereTo) {
  12. label = whereTo;
  13. }
  14. public String readLabel() {
  15. return label;
  16. }
  17. }
  18. public Destination dest(String s) {
  19. return new GDestination(s);
  20. }
  21. public Contents cont() {
  22. return new Content();
  23. }
  24. }

修改的部分用蓝色显示了。在这里我们给Goods类增加了一个private成员变量valueRate,意义是货物的价值系数,在内部类Content的方法value()计算价值时把它乘上。
我们发现,value()可以访问valueRate,这也是内部类的第二个好处 一个内部类对象可以访问创建它的外部类对象的内容,甚至包括私有变量!
这是一个非常有用的特性,为我们在设计时提供了更多的思路和捷径。要想实现这个功能,内部类对象就必须有指向外部类对象的引用。
Java编译器在创建内部类对象时,隐式的把其外部类对象的引用也传了进去并一直保存着。
这样就使得内部类对象始终可以访问其外部类对象,同时这也是为什么在外部类作用范围之外向要创建内部类对象必须先创建其外部类对象的原因。
有人会问,如果内部类里的一个成员变量与外部类的一个成员变量同名,也即外部类的同名成员变量被屏蔽了,怎么办?没事,Java里用如下格式表达外部类的引用:
outerClass.this 
有了它,我们就不怕这种屏蔽的情况了。
静态内部类
和普通的类一样,内部类也可以有静态的。不过和非静态内部类相比,区别就在于静态内部类没有了指向外部的引用。这实际上和C++中的嵌套类很相像了,Java内部类与C++嵌套类最大的不同就在于是否有指向外部的引用这一点上,当然从设计的角度以及以它一些细节来讲还有区别。
除此之外,在任何非静态内部类中,都不能有静态数据,静态方法或者又一个静态内部类(内部类的嵌套可以不止一层)。
不过静态内部类中却可以拥有这一切。这也算是两者的第二个区别吧。
局部内部类 
是的,Java内部类也可以是局部的,它可以定义在一个方法甚至一个代码块之内。

[java] view plain copy

  1. public class Goods1 {
  2. public Destination dest(String s) {
  3. class GDestination implements Destination {
  4. private String label;
  5. private GDestination(String whereTo) {
  6. label = whereTo;
  7. }
  8. public String readLabel() {
  9. return label;
  10. }
  11. }
  12. return new GDestination(s);
  13. }
  14. public static void main(String[] args) {
  15. Goods1 g = new Goods1();
  16. Destination d = g.dest("Beijing");
  17. }
  18. }

上面就是这样一个例子。在方法dest中我们定义了一个内部类,最后由这个方法返回这个内部类的对象。如果我们在用一个内部类的时候仅需要创建它的一个对象并创给外部,就可以这样做。当然,定义在方法中的内部类可以使设计多样化,用途绝不仅仅在这一点。
下面有一个更怪的例子:

[java] view plain copy

  1. public class Goods2 {
  2. private void internalTracking(boolean b) {
  3. if (b) {
  4. class TrackingSlip {
  5. private String id;
  6. TrackingSlip(String s) {
  7. id = s;
  8. }
  9. String getSlip() {
  10. return id;
  11. }
  12. }
  13. TrackingSlip ts = new TrackingSlip("slip");
  14. String s = ts.getSlip();
  15. }
  16. }
  17. public void track() {
  18. internalTracking(true);
  19. }
  20. public static void main(String[] args) {
  21. Goods2 g = new Goods2();
  22. g.track();
  23. }
  24. }

你不能在if之外创建这个内部类的对象,因为这已经超出了它的作用域。不过在编译的时候,内部类TrackingSlip和其他类一样同时被编译,只不过它由它自己的作用域,超出了这个范围就无效,除此之外它和其他内部类并没有区别。
匿名内部类 
java的匿名内部类的语法规则看上去有些古怪,不过如同匿名数组一样,当你只需要创建一个类的对象而且用不上它的名字时,使用内部类可以使代码看上去简洁清楚。它的语法规则是这样的:
new interfacename(){......}; 或 new superclassname(){......}; 
下面接着前面继续举例子:

[java] view plain copy

  1. public class Goods3 {
  2. public Contents cont() {
  3. return new Contents() {
  4. private int i = 11;
  5. public int value() {
  6. return i;
  7. }
  8. };
  9. }
  10. }

这里方法cont()使用匿名内部类直接返回了一个实现了接口Contents的类的对象,看上去的确十分简洁。
在java的事件处理的匿名适配器中,匿名内部类被大量的使用。例如在想关闭窗口时加上这样一句代码:

[java] view plain copy

  1. frame.addWindowListener(new WindowAdapter(){
  2. public void windowClosing(WindowEvent e){
  3. System.exit(0);
  4. }
  5. });

有一点需要注意的是,匿名内部类由于没有名字,所以它没有构造函数(但是如果这个匿名内部类继承了一个只含有带参数构造函数的父类,创建它的时候必须带上这些参数,并在实现的过程中使用super关键字调用相应的内容)。如果你想要初始化它的成员变量,有下面几种方法:
如果是在一个方法的匿名内部类,可以利用这个方法传进你想要的参数,不过记住,这些参数必须被声明为final。 
将匿名内部类改造成有名字的局部内部类,这样它就可以拥有构造函数了。 
在这个匿名内部类中使用初始化代码块。 
为什么需要内部类? 
java内部类有什么好处?为什么需要内部类?
首先举一个简单的例子,如果你想实现一个接口,但是这个接口中的一个方法和你构想的这个类中的一个方法的名称,参数相同,你应该怎么办?这时候,你可以建一个内部类实现这个接口。由于内部类对外部类的所有内容都是可访问的,所以这样做可以完成所有你直接实现这个接口的功能。
不过你可能要质疑,更改一下方法的不就行了吗?
的确,以此作为设计内部类的理由,实在没有说服力。
真正的原因是这样的,java中的内部类和接口加在一起,可以的解决常被C++程序员抱怨java中存在的一个问题 没有多继承。实际上,C++的多继承设计起来很复杂,而java通过内部类加上接口,可以很好的实现多继承的效果。

java静态与非静态区别

这里的静态,指以static关键字修饰的,包括类,方法,块,字段。

非静态,指没有用static 修饰的。

静态有一些特点:

1.全局唯一,任何一次的修改都是全局性的影响

2.只加载一次,优先于非静态

3.使用方式上不依赖于实例对象。

4.生命周期属于类级别,从JVM 加载开始到JVM卸载结束。

可参考 :http://blog.csdn.net/zhandoushi1982/article/details/8453522/。

关于静态内部类(嵌套类)和非静态内部类的区别,可参考:

http://www.jb51.net/article/74838.htm

(1)内部静态类不需要有指向外部类的引用。但非静态内部类需要持有对外部类的引用。

(2)非静态内部类能够访问外部类的静态和非静态成员。静态类不能访问外部类的非静态成员。他只能访问外部类的静态成员。

(3)一个非静态内部类不能脱离外部类实体被创建,一个非静态内部类可以访问外部类的数据和方法,因为他就在外部类里面。

/* 下面程序演示如何在java中创建静态内部类和非静态内部类 */
class OuterClass{
  private static String msg = "GeeksForGeeks";
  // 静态内部类
  public static class NestedStaticClass{
    // 静态内部类只能访问外部类的静态成员
    public void printMessage() {
     // 试着将msg改成非静态的,这将导致编译错误
     System.out.println("Message from nested static class: " + msg);
    }
  }
  // 非静态内部类
  public class InnerClass{
    // 不管是静态方法还是非静态方法都可以在非静态内部类中访问
    public void display(){
     System.out.println("Message from non-static nested class: "+ msg);
    }
  }
}
class Main
{
  // 怎么创建静态内部类和非静态内部类的实例
  public static void main(String args[]){
    // 创建静态内部类的实例
    OuterClass.NestedStaticClass printer = new OuterClass.NestedStaticClass();
    // 创建静态内部类的非静态方法
    printer.printMessage();
    // 为了创建非静态内部类,我们需要外部类的实例
    OuterClass outer = new OuterClass();
    OuterClass.InnerClass inner = outer.new InnerClass();
    // 调用非静态内部类的非静态方法
    inner.display();
    // 我们也可以结合以上步骤,一步创建的内部类实例
    OuterClass.InnerClass innerObject = new OuterClass().new InnerClass();
    // 同样我们现在可以调用内部类方法
    innerObject.display();
  }
}

Java提高篇-----详解内部类中对匿名内部类做了一个简单的介绍,但是内部类还存在很多其他细节问题,所以就衍生出这篇博客。在这篇博客中你可以了解到匿名内部类的使用、匿名内部类要注意的事项、如何初始化匿名内部类、匿名内部类使用的形参为何要为final。

一、使用匿名内部类内部类

匿名内部类由于没有名字,所以它的创建方式有点儿奇怪。创建格式如下:

[java] view plain copy

  1. new 父类构造器(参数列表)|实现接口()
  2. {
  3. //匿名内部类的类体部分
  4. }

在这里我们看到使用匿名内部类我们必须要继承一个父类或者实现一个接口,当然也仅能只继承一个父类或者实现一个接口。同时它也是没有class关键字,这是因为匿名内部类是直接使用new来生成一个对象的引用。当然这个引用是隐式的。

[java] view plain copy

  1. public abstract class Bird {
  2. private String name;
  3. public String getName() {
  4. return name;
  5. }
  6. public void setName(String name) {
  7. this.name = name;
  8. }
  9. public abstract int fly();
  10. }
  11. public class Test {
  12. public void test(Bird bird){
  13. System.out.println(bird.getName() + "能够飞 " + bird.fly() + "米");
  14. }
  15. public static void main(String[] args) {
  16. Test test = new Test();
  17. test.test(new Bird() {
  18. public int fly() {
  19. return 10000;
  20. }
  21. public String getName() {
  22. return "大雁";
  23. }
  24. });
  25. }
  26. }
  27. ------------------
  28. Output:
  29. 大雁能够飞 10000米

在Test类中,test()方法接受一个Bird类型的参数,同时我们知道一个抽象类是没有办法直接new的,我们必须要先有实现类才能new出来它的实现类实例。所以在mian方法中直接使用匿名内部类来创建一个Bird实例。

由于匿名内部类不能是抽象类,所以它必须要实现它的抽象父类或者接口里面所有的抽象方法。

对于这段匿名内部类代码其实是可以拆分为如下形式:

[java] view plain copy

  1. public class WildGoose extends Bird{
  2. public int fly() {
  3. return 10000;
  4. }
  5. public String getName() {
  6. return "大雁";
  7. }
  8. }
  9. WildGoose wildGoose = new WildGoose();
  10. test.test(wildGoose);

在这里系统会创建一个继承自Bird类的匿名类的对象,该对象转型为对Bird类型的引用。

对于匿名内部类的使用它是存在一个缺陷的,就是它仅能被使用一次,创建匿名内部类时它会立即创建一个该类的实例,该类的定义会立即消失,所以匿名内部类是不能够被重复使用。对于上面的实例,如果我们需要对test()方法里面内部类进行多次使用,建议重新定义类,而不是使用匿名内部类。

二、注意事项

在使用匿名内部类的过程中,我们需要注意如下几点:

      1、使用匿名内部类时,我们必须是继承一个类或者实现一个接口,但是两者不可兼得,同时也只能继承一个类或者实现一个接口。

      2、匿名内部类中是不能定义构造函数的。

      3、匿名内部类中不能存在任何的静态成员变量和静态方法。

      4、匿名内部类为局部内部类,所以局部内部类的所有限制同样对匿名内部类生效。

      5、匿名内部类不能是抽象的,它必须要实现继承的类或者实现的接口的所有抽象方法。

三、使用的形参为何要为final

参考文件:http://android.blog.51cto.com/268543/384844

我们给匿名内部类传递参数的时候,若该形参在内部类中需要被使用,那么该形参必须要为final。也就是说:当所在的方法的形参需要被内部类里面使用时,该形参必须为final。

为什么必须要为final呢?

首先我们知道在内部类编译成功后,它会产生一个class文件,该class文件与外部类并不是同一class文件,仅仅只保留对外部类的引用。当外部类传入的参数需要被内部类调用时,从java程序的角度来看是直接被调用:

[java] view plain copy

  1. public class OuterClass {
  2. public void display(final String name,String age){
  3. class InnerClass{
  4. void display(){
  5. System.out.println(name);
  6. }
  7. }
  8. }
  9. }

从上面代码中看好像name参数应该是被内部类直接调用?其实不然,在java编译之后实际的操作如下:

[java] view plain copy

  1. public class OuterClass$InnerClass {
  2. public InnerClass(String name,String age){
  3. this.InnerClass$name = name;
  4. this.InnerClass$age = age;
  5. }
  6. public void display(){
  7. System.out.println(this.InnerClass$name + "----" + this.InnerClass$age );
  8. }
  9. }

所以从上面代码来看,内部类并不是直接调用方法传递的参数,而是利用自身的构造器对传入的参数进行备份,自己内部方法调用的实际上时自己的属性而不是外部方法传递进来的参数。

直到这里还没有解释为什么是final?在内部类中的属性和外部方法的参数两者从外表上看是同一个东西,但实际上却不是,所以他们两者是可以任意变化的,也就是说在内部类中我对属性的改变并不会影响到外部的形参,而然这从程序员的角度来看这是不可行的,毕竟站在程序的角度来看这两个根本就是同一个,如果内部类该变了,而外部方法的形参却没有改变这是难以理解和不可接受的,所以为了保持参数的一致性,就规定使用final来避免形参的不改变。

      简单理解就是,拷贝引用,为了避免引用值发生改变,例如被外部类的方法修改等,而导致内部类得到的值不一致,于是用final来让该引用不可改变。

      故如果定义了一个匿名内部类,并且希望它使用一个其外部定义的参数,那么编译器会要求该参数引用是final的。

 

四、匿名内部类初始化

我们一般都是利用构造器来完成某个实例的初始化工作的,但是匿名内部类是没有构造器的!那怎么来初始化匿名内部类呢?使用构造代码块!利用构造代码块能够达到为匿名内部类创建一个构造器的效果。

[java] view plain copy

  1. public class OutClass {
  2. public InnerClass getInnerClass(final int age,final String name){
  3. return new InnerClass() {
  4. int age_ ;
  5. String name_;
  6. //构造代码块完成初始化工作
  7. {
  8. if(0 < age && age < 200){
  9. age_ = age;
  10. name_ = name;
  11. }
  12. }
  13. public String getName() {
  14. return name_;
  15. }
  16. public int getAge() {
  17. return age_;
  18. }
  19. };
  20. }
  21. public static void main(String[] args) {
  22. OutClass out = new OutClass();
  23. InnerClass inner_1 = out.getInnerClass(201, "chenssy");
  24. System.out.println(inner_1.getName());
  25. InnerClass inner_2 = out.getInnerClass(23, "chenssy");
  26. System.out.println(inner_2.getName());
  27. }
  28. }
时间: 2024-10-12 23:56:31

java中内部类的积累的相关文章

java中内部类的创建四种情况,三种方式,及内部数据访问权限

内部类和外部类的关系,及内部静态类的数据访问权限,声明方式. 第一种,在外部类内部声明使用内部类,内部类的类型为static和非 static类型,内部类数据类型为private,protected,public 类型的访问权限.外部类为非静态声明和权限如下: package com; public class Test1 { //@author 张春蕾 private class Name{ private int i =1; public int s = 2; protected int m

Java中内部类

内部类的规则: 1.内部类可以直接访问外部类中的成员,包括私有. 之所以可以直接访问外部类中的成员,是因为内部类中持有一个外部类的引用,格式:外部类名.this 2.外部类要访问内部类,必须建立内部类对象 访问格式: 1.当内部类定义在外部类的成员位置了,而且非私有,可以在外部其他类中. 可以直接建立内部类对象. 格式: 外部类类名.内部类名  变量名= new 外部类对象.new 内部类对象. Outer.inner out = new Outer().new inner(); 2.当内部类在

Java中内部类揭秘(一):外部类与非静态内部类的”相互可见性“

声明:本博客为原创博客,未经允许,不得转载!原文链接为 http://blog.csdn.net/bettarwang/article/details/27012421. 我们都知道,非静态内部类可以访问外部类的私有成员(包括私有变量和方法),这也正是使用非静态内部类与普通类的一个重要区别:非静态内部类是依赖于外部类对象而存在的,这种依赖就包括它要能自由地访问外部类对象的所有成员(因为private成员都可以访问了,其他权限的成员更不在话下.不过一般来说一个内部类只会访问外部类的部分成员而不是全

JAVA中内部类(匿名内部类)访问的局部变量为什么要用final修饰?

本文主要记录:在JAVA中,(局部)内部类访问某个局部变量,为什么这个局部变量一定需要用final 关键字修饰? 首先,什么是局部变量?这里的局部是:在方法里面定义的变量. 因此,内部类能够访问某局部变量,说明这个内部类不是在类中定义的内部类,而是在方法中定义的内部类,称之为:局部内部类. 局部变量的作用域:局部变量是在某个方法中定义,当该方法执行完成后,局部变量也就消失了.[局部变量分配在JVM的虚拟机栈中,这部分内存空间随着程序的执行自动回收],也即:局部变量的作用域是在 “方法的范围内”.

java中内部类的讲解

java中有一个内部类的概念,由于之前一直比较忙,没有单独拿出时间总结一下,今天我就把内部类的相关知识进行一下汇总,如果有不足之处,欢迎批评指正. 1)java内部类的概念.       在一个类的的内部定义的类被称为java的内部类 2)内部类的分类      根据内部类的位置不同,可以大致分为一下两类: 1.普通内部类又叫成员内部类,在方法体的外面定义的内部类 其中普通内部类又分为静态(static修饰的内部类)和非静态(非static修饰的内部类) 2.局部内部类又叫方法内部类,在方法体中

java中内部类的定义与访问规则

java内部类总结 简单来说,内部类就是在我们所熟悉的类中的里面再定义一个类 为什么需要内部类? 当我们描述事物时,事物之中还有事物,我们就用内部类描述事物 因为内部事物在使用外部事物的内容 我举一个例子 人体有心脏,血液,肝,脾,肺-……那么心脏该如何定义? 我们应该定义心脏为内部类,因为它在使用外部类(人体)的血液,氧气…… 实例1:内部类的基本结构 class Out /*外部类*/ { private int x=3; class In /*内部类*/ { private int y p

关于Java中内部类的一些概念整理

把一个类放到另一个类的内部定义,这个定义在其他类内部的类就被称为内部类. 内部类的作用: (1).内部类提供了更好的封装,可以把内部类隐藏在外部类之内,不允许同一个包中的其他类访问该类. (2).内部类成员可以直接访问外部类的私有数据,因为内部类被当成其外部类成员,同一个类的成员之间可以互相访问.但外部类不能访问内部类的实现细节. (3).匿名内部类适用于创建那些仅需要一次使用的类. (4).内部类比外部类可以多使用三个修饰符:private.protected.static--外部类不可以使用

Java 中内部类特性总结(吐血之作)

PS:今天花了整个下午时间看内部类相关的内容,因知识点多而杂,故记之如下. 一.内部类的作用 内部类看起来是一种代码隐藏机制:将类置于其他类的内部.它还了解外部类,并能与之通信:使用内部类可以实现闭包:内部类与接口使得多继承更完整,并且内部类是一个独立的实体(没有 is-a,仅仅是方法的封装). 二.基本特性 1)普通内部类为类的实例相关,可以看成是一个实例变量.内部类的类名由 "外部类.内部类" 确定. 内部类可以直接访问外部类的所有成员(包括 private成员),隐式或显式(外部

Java中内部类详解—匿名内部类

什么是内部类? 将一个类A定义在另一个类B里面,里面的那个类A就称为内部类,B则称为外部类.   成员内部类 定义在类中方法外的类. 定义格式: class 外部类 { class 内部类{ } } 在描述事物时,若一个事物内部还包含其他事物,就可以使用内部类这种结构.比如,汽车类Car 中包含发动机类Engine ,这时,Engine就可以使用内部类来描述,定义在成员位置. 代码举例: class Car { //外部类 class Engine { //内部类 } } 访问特点 成员内部类可