您的位置:首页 > 编程语言 > Java开发

Java之美[从菜鸟到高手演变]之类与对象(二)

2012-12-16 17:10 323 查看
类与对象之抽象类、接口、内部类
作者:egg

微博:http://weibo.com/xtfggef

出处:http://blog.csdn.net/zhangerqing

抽象类与接口:

这两个概念总是被放在一起讨论,因为他们有很多相似的地方,可以说接口本身就是完全抽象的,它要比抽象类更加“抽象”,为什么这么说?抽象类是一种类,里面除了有抽象方法外,还可以有具体的方法,而接口里面必须都是抽象的方法(有时可以在接口里定义类,后面会讲),尽管有时并没有显示的用abstract关键字声明。此处我们提到抽象方法,在Java中,凡是声明为形如:abstract void function()的方法,都是抽象方法,包含抽象方法的类就是抽象类,可以这么总结:抽象类中是可以没有抽象方法的;有抽象方法的类必须是抽象类;抽象类不一定有实体方法。

public class B extends A {

	@Override
	void a() {
		System.out.println();
	}

}
abstract class A {

	abstract void a();
	void b(){
		
	}
}
当我们继承抽象类时,必须重写其抽象方法。因为上述原因,所以抽象类不能被声明为final类型的,因为加final关键字的类保证不能被继承,因此为抽象类加final关键字,这个类就没法用了。抽象类只能被继承,不能被实例化!

声明为interface的类为接口,比抽象类更加抽象的一种机制。在接口中,我们不能提供任何实现,所有方法必须都是抽象的,可以不加abstract关键字,但是编译器对于接口中的方法,都是直接按抽象方法处理的。我们通过implements来实现某个接口。当我们实现某个接口时,必须重写其所有方法。

Java多继承

之前我们知道,采用interface为我们提供了一种将抽象与实现分离的结构化的方法,但是interface的作用远不止此,在Java中接口解决了一个非常重要的问题:多继承。在C++中,实现多重继承是比较简单的事儿,但是Java继承机制不允许多重继承,所以如果想要整合不同类的功能,就需要使用接口,我们来看个例子:

interface CanFight {void fight();}
interface CanFly {void fly();}
interface CanSwim {void swim();}
class ActionCharacter {public void fight(){}}
class Hero extends ActionCharacter implements CanFight, CanFly, CanSwim {

	@Override
	public void swim() {}

	@Override
	public void fly() {	}

}
public class Adventure {
	
	public static void t(CanFight x){x.fight();}
	
	public static void u(CanSwim x){x.swim();}
	
	public static void v(CanFly x){x.fly();}
	
	public static void w(ActionCharacter x){x.fight();}
	
	public static void main(String[] args) {
		Hero h = new Hero();
		t(h);
		u(h);
		v(h);
		w(h);
	}
}

我们可以看到:

1、Hero类中拥有了所有类的功能。

2、Hero可以和它实现的这些接口进行相互转换,当我们将hero对象做参数,传入Adventure类的各个方法时,Hero类向上转型了。(此处我们得出了一句话:在Java中,接口可以和实现了该接口的类相互转换)。讲到此处,我想总结下使用接口的好处:

1、接口可以实现向上转型,多个具有共同属性的类可以将它们的共同点提取出来,做成抽象,这样层次分明,统一管理。

2、接口不具有任何实现,最适合做基类。

总结一下抽象类与接口的区别和联系:

a) 抽象类是类,可以有实体方法。

b) 抽象类不能实现多继承,而接口可以。

c) 如果需要创建不带任何方法定义和成员变量的基类,则使用接口,如果类中需要有部分具体的实现,则使用抽象类。

d) 如果事先想要将某类设计为一个基类,那么首选接口。(注意c和d是接口的使用场景

接口可以通过继承(extends)接口,来拓展功能。接口中的域默认是final、static的,我们可以通过类名来直接引用。

内部类

创建:内部类的意思就是将类的定义放在另一个类的内部。有时合理的内部类使用会使代码更加简洁,令程序更加巧妙。而且作为外部类的成员,内部类可以访问外部类私有的成员变量。我们先来看看内部类的创建,分这么几种情况:

1、在外部类的非静态方法中创建内部类的实例。

public class InnerClass {
	class A{
		int a = 10;
		void b(){
			System.out.println("this is A.b()!");
		}
	}
	
	void build(){
		A a = new A();
		a.b();
	}
	
	public static void main(String[] args) {
		InnerClass ic = new InnerClass();
		ic.build();
	}
}


2、在外部类的静态方法中创建内部类的实例。

当在外部类的静态方法中创建内部类时,当内部类是静态的:

public class InnerClass {
	static class A{
		int a = 10;
		void b(){
			System.out.println("this is A.b()!");
		}
	}
	
	public static void main(String[] args) {
		InnerClass.build();
	}
	
	static void build(){
		A a = new A();
		a.b();
	}
}

当内部类是非静态的:

public class InnerClass {
	class A{
		int a = 10;
		void b(){
			System.out.println("this is A.b()!");
		}
	}
	
	public static void main(String[] args) {
		InnerClass ic = new InnerClass();
		InnerClass.A aa = ic.new A();
		aa.b();
	}
}

3、在内部类的非静态方法中创建外部类的实例。(使用外部类.this来创建外部类的实例)

public class InnerClass {
	class A{
		int a = 10;
		void build(){
			InnerClass ic = InnerClass.this;
			ic.a();
		}
	}
	
	void a(){
		System.out.println("this is InnerClass.a()!");
	}
}

4、在内部类的静态方法中创建外部类的实例。(直接通过new来创建)

public class InnerClass {
	static class A{
		int a = 10;
		static void build(){
			InnerClass ic = new InnerClass();
			ic.a();
		}
	}
	
	void a(){
		System.out.println("this is InnerClass.a()!");
	}
}

5、在其它类中创建内部类实例。(重点)

public class InnerClass {
	class A{
		void a(){
			System.out.println("this is A.a()!");
		}
	}
	static class C{
		void c(){
			System.out.println("this is C.c()!");
		}
	}
}
class B{
	public static void main(String[] args){
		/*创建非静态内部类*/
		InnerClass ic = new InnerClass();
		A a = ic.new A();
		a.a();
		
		/*创建静态内部类*/
		C c = new C();
		c.c();
	}
}

来看个深层嵌套的:

public class ABC {
	void a() {
		System.out.println("this is A.a()!");
	}

	class B {
		void b() {
			System.out.println("this is B.b()!");
		}

		class C {
			void c() {
				a();
				b();
				System.out.println("this is C.c()!");
			}
		}
	}

	public static void main(String[] args) {
		ABC abc = new ABC();
		ABC.B b = abc.new B();
		ABC.B.C c = b.new C();
		c.c();
	}
}

感觉越来越有意思了!此处最重要的就是这个”.new”操作符。同时,在类C内部调用a()和b()都很轻松,就说明内部类就相当于一个普通的变量,哪怕是private权限的,也一样,直接调用,因为它们在同一个类中。匿名内部类的创建:

interface A {
	void a();
}

public class InnerClass_NoName {

	public A test() {
		return new A() {
			public void a() {
				System.out.println("");
			}
		};
	}

	public static void main(String[] args) {
		InnerClass_NoName icn = new InnerClass_NoName();
		A a = icn.test();
		a.a();
	}
}

典型的情况是,内部类继承自某个类或实现某个接口,内部类的代码操作创建其的外围类的对象。所以你可以认为内部类提供了某种进入其外围类的窗口。使用内部类最吸引人的原因是:每个内部类都能独立地继承自一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对于内部类都没有影响。如果没有内部类提供的可以继承多个具体的或抽象的类的能力,一些设计与编程问题就很难解决。从这个角度看,内部类使得多重继承的解决方案变得完整。接口解决了部分问题,而内部类有效地实现了“多重继承”。一般情况,内部类不宜过长,否则就会显得头重脚轻。

使用匿名内部类应该注意:

a) 匿名内部类不能有构造方法
b) 匿名内部类不能定义任何静态成员、方法和类。
c) 匿名内部类不能是public,protected,private,static。
d) 只能创建匿名内部类的一个实例。
e) 一个匿名内部类一定是在new的后面,用其隐含实现一个接口或实现一个类。
f) 因匿名内部类为局部内部类,所以局部内部类的所有限制都对其生效。
嵌套类:
普通的内部类持有外围类的一个引用,所以可以与外部类保持联系,而当我们需要嵌套类的时候,我们需要使用static关键字,这样内部类就断开了和外部类的联系,不能从内部类的对象中访问非静态的外部类。

public class InnerClass {
	
	static class A{
		static int a = 10;
		static void a(){
			System.out.println("this is A.a()!");
		}
	}
}


接口内部的类:

public interface Interface_Class {
	void say();
	class IC implements Interface_Class{
		@Override
		public void say() {
			System.out.println("hello");
		}
		public static void main(String[] args) {
			new IC().say();
		}
	}
}

适合于创建公共代码,供所有实现了该接口的类使用。

内部类的继承,我们说过,内部类持有对外部类的引用,所以,在继承的时候,我们需要初始化这个“隐藏”着的引用,请看下面的代码:

class AAA {
	class BBB {

	}
}

public class InnerClass_Extends extends AAA.BBB {
	public InnerClass_Extends(AAA aaa) {
		aaa.super();
	}

	public static void main(String[] args) {
		AAA aaa = new AAA();
		InnerClass_Extends ice = new InnerClass_Extends(aaa);
	}
}

最后,我们总结下使用内部类的原因:每个内部类都能独立继承自一个接口的实现,和外部类没有任何关系(不论外部类是否实现了该接口)。

说的再简单一点就是,内部类是Java多继承机制的完美补充,为什么这样说?我们说过,实现多继承靠的是接口,光从类的角度说是没有多继承一说的。但是,如果现在非得用抽象类实现多继承,很明显是不可能的,此处就必须使用内部类。举个例子:

class AA{
	
}
abstract class BB{
	
}
class CC extends AA{
	BB makeB(){
		return new BB(){
			
		};
	}
}
public class Multi_Extends {
	
	static void takesA(AA a){}
	static void takesB(BB b){}
	
	public static void main(String[] args) {
		CC c = new CC();
		takesA(c);
		takesB(c.makeB());
	}

}
这样就实现了继承内部类。

本章即将告一段落,欢迎大家积极补充,并对文章的遗漏、疏忽之处提出建议!下一章,笔者将主要介绍下类的继承机制,欢迎读者朋友们继续阅读、学习!

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: