Thinking in Java之内部类

        前言

          学习Java已经有一段日子了,最近的日子笔者在重新对java进行再学习。不过这个阶段的学习

    笔者不会再着眼于具体的语法哪些细枝末节的东西了,这个阶段的学习中笔者将会对以前学习的

    模糊的,遗漏的知识概念做一些相关性的总结。今天,恰好看到内部类这块了,记得以前对内部类

    的使用就有一些模糊,因此专门就内部类做一些总结。

      内部类概念

               所谓内部类就是指在一个外部类中再定义一个类(内部类),这样内部类就作为一个成员依附于

          外部类而存在。不过在使用内部类的时候需要注意的是内部类可以static,protect,private,但是

          外部类只能使用public和缺省的包访问权限.

            若非这两种编译出错: 

            Illegal modifier for the class Outer; only public, abstract & final are permitted  

package com.kiritor;
public class Outer {
	private String type;

	public String getType() {
		return type;
	}

	public void setType(String type) {
		this.type = type;
	}

	class Inner {
		private String type;

		public String getType() {
			return type;
		}

		public void setType(String type) {
			this.type = type;
		}

	}
}

      内部类的意义

                 简单看来内部类好像就是一种代码隐藏机制:将类至于其他类的内部.不过内部类远不止这样

          它了解外部类,能够和外部类进行必要的通信。

                  1、封装一些别人不想知道的操作.

                  2、内部类可以访问创建它的外部类对象的内容,甚至包括了private的变量.

            内部类同样可以实现接口,继承基类,这使得java中的多继承变得完整.。我们可以使用内部类

            的方式模拟出多继承的效果。

                 通过内部类继承基类,外部类创建内部类对象,并使用内部类提供的方法,这样就变相的实现了

           多继承的效果.

public class Graduate{  
   
    private Graduate_stu  gaduate_stu= new Graduate_stu();  
   
    private Graduate_emp  graduate_emp = new Graduate_emp();  
   
    private class Graduate_stu  extends Student{  
   
         public void getName() {  
            .... 
        }  
    }  
   
    private class Graduate_emp extends Employee{  
   
         public double getMoney()
            {
                return 0.0;
             }
    }  
   
    public void getName() {  
        gaduate_stu.getName();  
    }  
   
    public double getMoney() {  
        graduate_emp .getMoney();  
    }  
}  
            只是用代码简单的模拟了一下!
                 内部类还有一个颇具吸引力的特点,那就是内部类和外部类对于接口的继承是"分离"的

            相互不存在影响的,基于现实的情况,有时候我们实现一个接口,但是接口的方法在此类

            中已经有定义了,对于这种情况,我们就可以使用内部类实现该接口,实现其方法,因为内

           部类对于外部类的成员是可访问的,因此使用内部类的方法就解决可该问题。

        内部类的分类

                   我们现在知道内部类是放在外部类中的,根据内部类不同的"位置"和特性,内部类可以

             分为以下几类:

                           ●  成员内部类

                           ●  局部内部类

                           ●  静态内部类(嵌套类)

                           ●  匿名内部类

               对于其具体的特性和用法下面介绍

           成员内部类

             内部类作为外部类的一个成员存在,与外部类的方法,属性并列.                    

package com.kiritor;
public class Outer {
	private String type="Outer Class";
	private static int flag = 1;

	public String getType() {
		return type;
	}

	public void setType(String type) {
		this.type = type;
	}
	@Override
	public String toString() {
		System.out.println(""+getType()+":"+this.flag);
		Inner inner = new Inner();
		inner.toString();//外部类的非静态方法访问内部类的方法
		//外部类的静态方法访问与其是一样的,不做演示了.
		return super.toString();
	}

	class Inner {
		private String type="Inner Class";
        private   int flag=2;//这里成员内部类中不允许定义静态成员
		public String getType() {
			return type;
		}

		public void setType(String type) {
			this.type = type;
		}
		public String toString() {
			System.out.println(""+getType()+":"+this.flag);
			System.out.println(""+Outer.this.getType()+Outer.this.flag);//若有变量重名,通过此种方式访问
			return super.toString();
		}
		
		
	}
	public static void main(String[] args) {
		Outer outer = new Outer();
		outer.toString();
		Outer.Inner inner = outer.new Inner();//通过此种方式new inner
		inner.toString();
	}
}
            

              Tips:在创建一个内部类的时候除非你已经有了一个外部类对象,否则不可能生成

                 方法内部类对象,因为内部类对象会悄悄的链接到创建他的外部类的对象,没有外部类对象

             自然也就不可能生成内部类对象了,不过还需注意的是内部类是一个在编译时的概念,一旦编译

             通过,就会成为完全不同的两个类,也就是会出现Outer,class和Outer$Inner,class两个字节码

             文件。

          

              局部内部类

                   在方法中定义的内部类称为局部内部类.它与局部变量类似,因此局部内部类是不能有访问

           修饰符的,因为它不是外部类成员,但是他可以访问当前方法中的代码块的常量,和外部类的所有

          成员.

package com.kiritor;

public class Outer {
	private String type = "Outer Class";
	private static int flag = 1;

	public String getType() {
		return type;
	}

	public void setType(String type) {
		this.type = type;
	}

	@Override
	public String toString() {
		System.out.println("" + getType() + ":" + this.flag);
		return super.toString();
	}

	public void innerInfo() {
		final String innerFinal = "可以访问方法体内的常量";
		class Inner {
			private String type = "Inner Class";
			private int flag = 2;// 这里成员内部类中不允许定义静态成员

			public String getType() {
				return type;
			}

			public void setType(String type) {
				this.type = type;
			}

			public String toString() {
				System.out.println("" + getType() + ":" + this.flag
						+ innerFinal);
				System.out.println("" + Outer.this.getType() + Outer.this.flag);// 若有变量重名,通过此种方式访问
				return super.toString();
			}

		}
		new Inner().toString();//注意是通过这种方式调用内部类的方法的!
	}

	public static void main(String[] args) {
		Outer outer = new Outer();
		outer.toString();
		outer.innerInfo();
	}
}

          静态内部类(嵌套类)

                 前面两种内部类和变量类似,这里的变量就是成员变量,和局部变量,可以参照进行对比

              如果你不需要内部类对象与其外部类对象之间有联系,那你可以将内部类声明为static的,这就

              是静态内部类.我们需要明白的是:普通的内部类对象隐含的保存了一个外部类对象的引用

                   但是当内部类为static的时候这种“特性”也就没有了,这意味着:

                         1、创建静态内部类对象的时候并不需要外部类对象

                         2、不能通过静态内部类对象访问非静态的外部类对象了。

              看例子:

package com.kiritor;

public class Outer {
    private String type = "Outer Class";
    private static int flag = 1;

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    @Override
    public String toString() {
        System.out.println("" + getType() + ":" + this.flag);
        Inner.info();//外部类访问内部类的静态成员:内部类.静态成员(静态方法)
        Inner inner = new Inner();//这里生成一个内部类对象不再需要通过外部类对象了
        inner.toString();//外部类访问静态内部类的非静态成员或方法必须new一个对象
        System.out.println(inner.type);
        return super.toString();
    }

    static class Inner {
            private String type = "Inner Class";
            private int flag = 2;
            private static String info="Inner Class 2";
            //静态内部类中可以有非静态方法、属性
            public String getType() {
                return type;
            }

            public void setType(String type) {
                this.type = type;
            }

            public  static void info()
            {
                System.out.println(info);
            }
            public String toString() {
                System.out.println("" + getType() + ":" + this.flag
                        );
                //System.out.println("" + Outer.getType() + Outer.this.flag);// 若有变量重名,通过此种方式访问
                return super.toString();
            }

        }

    public static void main(String[] args) {
        Outer outer = new Outer();
        outer.toString();
        
    }
} 
                可以看出的是:生成一个内部类对象不再需要通过一个外部类对象了,这也是静态内部类和

        成员内部类的区别:Outer.Inner in = new Outer.Inner();

           匿名内部类

             简单的说匿名内部类就是没有名字的类了,这在GUI编程里面是较为常见的,给个例子:

             

package com.kiritor;

import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

import javax.swing.JButton;
import javax.swing.JFrame;

public class MyFrame extends JFrame{
	private JButton button = null;
	public MyFrame() {
		this.setSize(200, 200);
		this.setVisible(true);
		button = new JButton("匿名内部类");
		button.addMouseListener(new MouseListener() {//一个匿名的类
			
			@Override
			public void mouseReleased(MouseEvent e) {
				// TODO Auto-generated method stub
				
			}
			
			@Override
			public void mousePressed(MouseEvent e) {
				// TODO Auto-generated method stub
				
			}
			
			@Override
			public void mouseExited(MouseEvent e) {
				// TODO Auto-generated method stub
				
			}
			
			@Override
			public void mouseEntered(MouseEvent e) {
				// TODO Auto-generated method stub
				
			}
			
			@Override
			public void mouseClicked(MouseEvent e) {
				// TODO Auto-generated method stub
				
			}
		});
		this.add(button);
		
		
	}
    
}
          对于匿名内部类,笔者现就不做总结了,之后会找个时间理解一下.

          内部类的相关问题

                    下面讨论的是内部类中的一些有趣的问题!

                         内部类能否被"重载"、“继承”?

               内部类重载问题

                       假设如果你创建了一个外部类,并定义了一个内部类,之后继承外部类并重新定义内部类

                   的时候会发生什么呢?

package com.kiritor;

class Outer {
	public Outer() {
		System.out.print("Outer:");
		new Inner();
	}

	class Inner {

		public Inner() {
			System.out.println("Inner");
		}

	}

}

public class Outer2 extends Outer {
	class Inner {

		public Inner() {
			System.out.println("outer2:Inner");
		}
	}

	public static void main(String[] args) {
		new Outer2();

	}

}
            看一看输出情况:Outer:Inner
                缺省的构造器Outer2()是编译器自动生成的,他会先调用父类的构造器,通过结果可以看出

          虽然创建的是子类对象,但是 内部类并不是使用的"重载"过的.这说明档你继承了某个外部类

          的时候,内部类并未发生特别变化,当然明确的继承某个内部类的方式除外!

         

package com.kiritor;

class Outer {
	public Outer() {
		System.out.print("Outer:");
		new Inner();
	}

	class Inner {

		public Inner() {
			System.out.println("Inner");
		}

	}

}

public class Outer2 extends Outer {
	class Inner extends com.kiritor.Outer.Inner{

		public Inner() {
			System.out.println("outer2:Inner");
		}
	}

	public Outer2() {
		new Inner();
	}
	public static void main(String[] args) {
		new Outer2();

	}

}
           明确继承之后的输出结果为:

              

         内部类的继承问题

                有时候我们只是需要继承内部类,但是内部类的构造器又必须用到外部对象的引用

           , 因此在继承一个内部类的时候就有点特别了,主要的问题在于外部类对象的引用必须

           初始化,而在被继承类中并不存在,也就是单一继承内部类的时候,没有内部类与其外部类

           的一种关联.

               可以使用一下方式解决:

      

package com.kiritor;

import com.kiritor.Outer.Inner;

class Outer {
	public Outer() {
		System.out.print("Outer:");
		new Inner();
	}

	class Inner {

		public Inner() {
			System.out.println("Inner");
		}

	}


}

public class Inner2 extends Outer.Inner {
  Inner2(Outer outer)
   {
	   outer.super();
	   //构造器只能是这种方式的
	   System.out.println("只能为此种构造器");
   }
 
public static void main(String[] args) {
	new Inner2(new Outer());
}
}
      输出结果为:

          Outer:Inner
           Inner
          只能为此种构造器
        可以看出的是,Inner2只是集成了内部类,但是其缺省的构造器并不能用,而且仅仅传递一个

    外部类的引用还不够,还必须首先调用外部类的构造方法.这样才提供了内部类与外部类对象

    的引用关联,才能够通过编译的.

     

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
《Thinking in Java》是一本经典的Java编程入门教材,通过阅读该书可以系统地学习Java编程的基础知识和高级概念。阅读过程中,我结合自己的学习体验和实践,进行了详细的学习笔记。 首先,该书从基础语法开始介绍,包括数据类型、控制语句、数组等。对于初学者来说,这些基础知识是最基本的,通过书中的示例代码和解析,我能够更好地理解这些概念和语法规则。 其次,书中对面向对象编程进行了深入的讲解。通过学习面向对象的思想,我明白了类、对象、继承、多态等概念的含义和使用方法。同时,书中还讲解了接口、内部类、异常处理等较为高级的概念,极大地拓宽了我的Java知识面。 另外,该书还介绍了Java的常见类库和工具,如字符串操作、集合框架、输入输出、线程等。这些内容对于实际开发非常有用,而且书中的示例代码也能帮助我更好地理解和应用这些类库和工具。 此外,该书通过大量的实例和案例,生动地展示了Java编程的实战应用。这些实例涵盖了各种不同的应用场景,从简单的程序到复杂的项目,都有所涉及。通过分析这些实例,我不仅可以学习到实际编程的技巧,还能提高自己的解决问题的能力。 总的来说,读完《Thinking in Java》后,我对Java编程有了更深入的理解和掌握。通过学习笔记的整理,我不仅复习了各个知识点,还加深了对这些概念的理解。希望这份学习笔记能够帮助到其他想要学习Java的同学,让他们能够更快地入门和掌握这门编程语言。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值