Java核心编程三:类的继承、反射、接口和内部类
2013-09-19 07:45
323 查看
1 继承
1.1 继承的实现
继承的基本语法如下:
Java采用关键字extends来替换C系统中的:来标识继承,但只支持公有继承。
1.2 构造函数
派生类的构造函数如果要初始化基类,则必须至于第一行调用super();C++则需要在初始化列表中调用基类名称的构造器。
如果没有显式的调度,则是编译器调用基类的默认构造函数。此时若基类没有默认构造函数,但存在其他构造函数,则编译过程出错。
1.3 多态
对于基类的私有成员,派生类只能通过基类的方法来获取,并通过super告诉编译器,去调用基类上的方法。
在JAVA中对象变量是多态的,不需要像C++中必须使用引用或指针才能实现多态。并且多态行为是默认的,不需要将方法声明为虚拟。但若希望实现多态,仍然需要在基类中实现此方法的一个版本,并在派生类中进行覆盖。
如果想让一个方式或属性不能被子类覆盖,可以声明为final方法。若一个类不希望有子类,可以声明为final类。
在覆盖一个方法时,其可见性不能被缩小。
1.4 动态绑定
动态绑定是指在运行时索引正确对象上的正确方法的技术。可以在运行时进行查找。Java对此进行了优化,在编译期将所有调用的路径记录下来,并保存起来,运行时只需要查找此表即可。
1.5 类型转换
派生类型可以轻易的转换为基类型,但向下的转换可能会导致运行时类型错误,因而在转换时要用instanceof来检验,这点也适用于null对象。
1.6 抽象类
可以使用abstract关键字声明方法,这样的方法将不包含实现体。而包含了抽象方法的类必须声明为抽象类。
抽象类也可以包含属性和非抽象方法,但其不能实例化。当然我们仍可以定义抽象类的变量来引用子类对象。
子类可以实现部分抽象方法,但这样子类也必须是抽象的。若实现了全部抽象方法,子类便不再抽象。
对于不包含抽象方法的类,也可以声明为抽象的。
2 Object类
Java中所有类都继承自Object类。除了原始类型外,所有形式的数据也都继承自Object.
equals() 和== 一样通过比较两个对象是否指向同一对象来比较相等。
hashCode() 计算对象的散列码
toString() 导出对象的字符串表示,这样当将对象送给print时,会自动调用对象的toString。
3 泛型数组列表
ArrayList<T>(capacity) 构造一个指定容量大小的列表
add(T) 增加一个元素
ensureCapacity() 扩展容器空间
size() 返回元素个数
trimToSize() 收缩到指定个数
get(index) 返回指定位置上的元素
set(idx,T) 设置指定位置元素
remove(idx) 移除指定位置元素
4 box与unbox
基本类型都有与之对应的类类型,而且可以方便的从基本类型转换为类类型。而泛型类不支持基本类型的元素。
需要注意的是这两个操作是编译器来完成的,而不是由虚拟机来实现的。
5 反射
5.1 Class
Class类类专门用于保存Java类的元信息,有三种方式获取到它的实例。
I 调用对象的getClass()可以返回此类的实例,其中保存了java类的属性信息,如类名、字段名、方法名等。
II 通过静态函数和类名来生成:Class.forName(strName)
III 访问类型的属性,T.class
可以通过元类对象来创建对象实例,调用newInstance()即可。
5.2 分析类的接口
getFields() 将返回类的所有属性数组,包括基类,只有public的
getDeclaredFields() 返回类属性数组,不包括基类
getField(String name) 根据字段名称返回指定域,返回类属性,不包括基类,必须为public
getMethods() //返回类包括基类的方法
getDeclaredMethod(String name,Class[] parmType) //根据指定的参数类型数据返回指定的参数
getConstructors()
getDeclaredConstructors()
Field类保存了类的字段属性信息
Method类保存了方法属性信息
Constructor类保存了构造器的属性信息
Modifier类保存声明的修改器的信息如static ,private等
在得到了这些类后,可以调用其上的方法
getExceptionType() 获取方法抛出的异常类型的元类数组
getModifiers() 其返回一个整数,结果可以用isAbstract() isFinal(),isInterface(),isPrivate(),...,isStatic()来分析
getName() 获取方法、属性或构造函数的名字
getParameterTypes() 返回构造函数或方法的参数类型元类数组
getReturnType() 返回方法的返回值的类型元类
5.3 分析对象的接口
AccessibleObject是Field,Method等的基类。其上有如下方法,可以另子类调用。
setAccessible(flag) 设置字段的可访问性,对于private字段,反射只有设置为true时,才可访问。
isAccessible()
通过类获取类对象应该有的Field对象后,可以获取或设置域在对象上的值。
Object get(object)
void set(obj,newVal)
5.4 方法指针
通过Method的实例,可以拿到一个方法的指针。它可以通过Object invode(obj,Object [])来进行调用。对于静态方法,obj为null。
其返回结果是Object类型的,因此需要进行一定的类型转换。
5.5 反射示例
6 枚举类型
声明类型:enum Week {MONDAY,TUESDAY,...};
声明对象:Week week = Week.MONDAY;
enum声明的类型都继承自Enum类,它有一个静态方法values()返回所有常量的数组。
enum对象还可通过Enum的静态方法valueOf(Class eType,String val)来设置一个枚举类型的常量值。
7 接口
7.1 接口声明
必须在单独的文件中声明接口,文件名与接口名相同。
接口中的方法自动为public的,不需要特殊声明,但在实现类中,必须声明为public的,否则便变为包可见的。接口中不能声明静态方法和实例属性,只能声明常量,且被自动标记为public static final。
接口也可以实现为泛型类型如
Java语言提供了Comparable类和Comparable<T>两个接口,前者接受Object类型的参数,后者接受T类型的参数。
7.2 接口使用
interface rule = new ConRule();//
接口类不能用new实例化,但可以通过声明变量指向实现接口的对象。
可以使用instanceof判断对象是否实现了接口。
接口之间可以进行继承,且支持多重继承。之所有引入接口,是因为其不允许多类的重继承。
7.3 接口与回调
Timer类可以接受一个对象,以定时执行一些回调函数。只要这个对象实现了特定的接口即可。
java.util.Timer包含了所需要的后台调度类,只需要实现TimerTask.run()方法即可。
8 对象复制
在Object基类提供了一个受保护的clone()方法,可以返回对象的一个浅拷贝。通常情况下,这并不是你想要的,因此需要像C++一样,在自己的类中实现自己的clone()函数,以覆盖基类的行为。
只有需要实现深copy的类,才需要自己实现clone()接口。
9 内部类
Java的内部类有以下三个特点:
1 内部类的方法可以访问此类所定义的外部类作用域中的数据,包括私有数据。
2 内部类可以对同一个包中的其他类隐藏起来。
3 当需要定义一个回调函数时,可以使用匿名内部类。
9.1 内部类访问外部对象状态
内部类可以定义为private的,这样其只在外部类的内部可见。编译器会为内部类合成构造函数,或为其构造函数添加一个指向外部类对象实例的引用。这样使得其可以访问到其外部类对象。
9.2 内部类使用语法
在外部类创建内部类: Outobj.new InnerClass(params)
在外部类作用域外,引用内部类:OuterClass.InnerClass
9.3 内部类实现
内部类可以访问外部类的私有成员,是一个编译器现象,JVM并不了解这个事情。为了实现这个目的,编译器会将外部类的对象this指针传递给内部类,并在外部类上增加相应的static函数,以访问外部类的相应私有成员。
如果不希望内部类引用外部类,则可以将其声明为static的。
9.4 方法内部类
可以在方法中定义内部类。方法中的内部类,可以访问外部方法的final类型的常量局部变量。
编译器的实现更为简单,将内部类所引用的外部局部变量作为构造器参数复制给类,并作为其成员。
9.5 匿名内部类
如果类只使用一次,则可以创建为匿名的。使用语法为:
匿名内部类如果过长,会不利于代码的理解,应该限制使用。
示例:
10 反射代理
代理是一种支持在运行时创建支持特定接口的类对象的方法,类的代码可以通过类加载器从远程或本地进行加载。
Object Proxy.newProxyInstance(ClassLoader cl,Class[] interfaces,InvocationHandler ih)
Object invoke(Object proxy,Method method,Object[] args)
而被代理的对象,则通过实现InvocationHandler接口的invoke()方法将对象进行包装。
这里有个要求,就是被代理的类需要实现了特定的接口,如果一个类不是实现自接口,则无法这样使用。
1.1 继承的实现
继承的基本语法如下:
class Manage extends Employee { public Manage() { super(); //Manage member init } }
Java采用关键字extends来替换C系统中的:来标识继承,但只支持公有继承。
1.2 构造函数
派生类的构造函数如果要初始化基类,则必须至于第一行调用super();C++则需要在初始化列表中调用基类名称的构造器。
如果没有显式的调度,则是编译器调用基类的默认构造函数。此时若基类没有默认构造函数,但存在其他构造函数,则编译过程出错。
1.3 多态
对于基类的私有成员,派生类只能通过基类的方法来获取,并通过super告诉编译器,去调用基类上的方法。
在JAVA中对象变量是多态的,不需要像C++中必须使用引用或指针才能实现多态。并且多态行为是默认的,不需要将方法声明为虚拟。但若希望实现多态,仍然需要在基类中实现此方法的一个版本,并在派生类中进行覆盖。
如果想让一个方式或属性不能被子类覆盖,可以声明为final方法。若一个类不希望有子类,可以声明为final类。
在覆盖一个方法时,其可见性不能被缩小。
1.4 动态绑定
动态绑定是指在运行时索引正确对象上的正确方法的技术。可以在运行时进行查找。Java对此进行了优化,在编译期将所有调用的路径记录下来,并保存起来,运行时只需要查找此表即可。
1.5 类型转换
派生类型可以轻易的转换为基类型,但向下的转换可能会导致运行时类型错误,因而在转换时要用instanceof来检验,这点也适用于null对象。
1.6 抽象类
可以使用abstract关键字声明方法,这样的方法将不包含实现体。而包含了抽象方法的类必须声明为抽象类。
抽象类也可以包含属性和非抽象方法,但其不能实例化。当然我们仍可以定义抽象类的变量来引用子类对象。
子类可以实现部分抽象方法,但这样子类也必须是抽象的。若实现了全部抽象方法,子类便不再抽象。
对于不包含抽象方法的类,也可以声明为抽象的。
abstract class Person { abstract String getName(); }
2 Object类
Java中所有类都继承自Object类。除了原始类型外,所有形式的数据也都继承自Object.
equals() 和== 一样通过比较两个对象是否指向同一对象来比较相等。
hashCode() 计算对象的散列码
toString() 导出对象的字符串表示,这样当将对象送给print时,会自动调用对象的toString。
3 泛型数组列表
ArrayList<T>(capacity) 构造一个指定容量大小的列表
add(T) 增加一个元素
ensureCapacity() 扩展容器空间
size() 返回元素个数
trimToSize() 收缩到指定个数
get(index) 返回指定位置上的元素
set(idx,T) 设置指定位置元素
remove(idx) 移除指定位置元素
4 box与unbox
基本类型都有与之对应的类类型,而且可以方便的从基本类型转换为类类型。而泛型类不支持基本类型的元素。
需要注意的是这两个操作是编译器来完成的,而不是由虚拟机来实现的。
5 反射
5.1 Class
Class类类专门用于保存Java类的元信息,有三种方式获取到它的实例。
I 调用对象的getClass()可以返回此类的实例,其中保存了java类的属性信息,如类名、字段名、方法名等。
II 通过静态函数和类名来生成:Class.forName(strName)
III 访问类型的属性,T.class
可以通过元类对象来创建对象实例,调用newInstance()即可。
5.2 分析类的接口
getFields() 将返回类的所有属性数组,包括基类,只有public的
getDeclaredFields() 返回类属性数组,不包括基类
getField(String name) 根据字段名称返回指定域,返回类属性,不包括基类,必须为public
getMethods() //返回类包括基类的方法
getDeclaredMethod(String name,Class[] parmType) //根据指定的参数类型数据返回指定的参数
getConstructors()
getDeclaredConstructors()
Field类保存了类的字段属性信息
Method类保存了方法属性信息
Constructor类保存了构造器的属性信息
Modifier类保存声明的修改器的信息如static ,private等
在得到了这些类后,可以调用其上的方法
getExceptionType() 获取方法抛出的异常类型的元类数组
getModifiers() 其返回一个整数,结果可以用isAbstract() isFinal(),isInterface(),isPrivate(),...,isStatic()来分析
getName() 获取方法、属性或构造函数的名字
getParameterTypes() 返回构造函数或方法的参数类型元类数组
getReturnType() 返回方法的返回值的类型元类
5.3 分析对象的接口
AccessibleObject是Field,Method等的基类。其上有如下方法,可以另子类调用。
setAccessible(flag) 设置字段的可访问性,对于private字段,反射只有设置为true时,才可访问。
isAccessible()
通过类获取类对象应该有的Field对象后,可以获取或设置域在对象上的值。
Object get(object)
void set(obj,newVal)
5.4 方法指针
通过Method的实例,可以拿到一个方法的指针。它可以通过Object invode(obj,Object [])来进行调用。对于静态方法,obj为null。
其返回结果是Object类型的,因此需要进行一定的类型转换。
5.5 反射示例
public class TestReflect { public int value; public String name; public TestReflect() { value = 1; name = "lipeng"; } public void function(String s) { System.out.println(s); } public static void main(String[] args) { TestReflect rf = new TestReflect(); try { Field field = rf.getClass().getField("name"); Method method = rf.getClass().getDeclaredMethod("function", String.class); String val = field.get(rf).toString(); System.out.println(val); method.invoke(rf, "Hello world"); } catch(Exception e) { e.printStackTrace(System.out); } } }
6 枚举类型
声明类型:enum Week {MONDAY,TUESDAY,...};
声明对象:Week week = Week.MONDAY;
enum声明的类型都继承自Enum类,它有一个静态方法values()返回所有常量的数组。
enum对象还可通过Enum的静态方法valueOf(Class eType,String val)来设置一个枚举类型的常量值。
7 接口
7.1 接口声明
必须在单独的文件中声明接口,文件名与接口名相同。
interface IRule { int PI = 3.14; int method(); } class ConRule implements IRule { public int method(); }
接口中的方法自动为public的,不需要特殊声明,但在实现类中,必须声明为public的,否则便变为包可见的。接口中不能声明静态方法和实例属性,只能声明常量,且被自动标记为public static final。
接口也可以实现为泛型类型如
interface IRule<T> { int method(T arg); } class ConRule implements IRule<Person> { int method(Person p) { printf(p.toString()); } }
Java语言提供了Comparable类和Comparable<T>两个接口,前者接受Object类型的参数,后者接受T类型的参数。
7.2 接口使用
interface rule = new ConRule();//
接口类不能用new实例化,但可以通过声明变量指向实现接口的对象。
可以使用instanceof判断对象是否实现了接口。
接口之间可以进行继承,且支持多重继承。之所有引入接口,是因为其不允许多类的重继承。
7.3 接口与回调
Timer类可以接受一个对象,以定时执行一些回调函数。只要这个对象实现了特定的接口即可。
java.util.Timer包含了所需要的后台调度类,只需要实现TimerTask.run()方法即可。
8 对象复制
在Object基类提供了一个受保护的clone()方法,可以返回对象的一个浅拷贝。通常情况下,这并不是你想要的,因此需要像C++一样,在自己的类中实现自己的clone()函数,以覆盖基类的行为。
只有需要实现深copy的类,才需要自己实现clone()接口。
9 内部类
Java的内部类有以下三个特点:
1 内部类的方法可以访问此类所定义的外部类作用域中的数据,包括私有数据。
2 内部类可以对同一个包中的其他类隐藏起来。
3 当需要定义一个回调函数时,可以使用匿名内部类。
9.1 内部类访问外部对象状态
内部类可以定义为private的,这样其只在外部类的内部可见。编译器会为内部类合成构造函数,或为其构造函数添加一个指向外部类对象实例的引用。这样使得其可以访问到其外部类对象。
9.2 内部类使用语法
在外部类创建内部类: Outobj.new InnerClass(params)
在外部类作用域外,引用内部类:OuterClass.InnerClass
9.3 内部类实现
内部类可以访问外部类的私有成员,是一个编译器现象,JVM并不了解这个事情。为了实现这个目的,编译器会将外部类的对象this指针传递给内部类,并在外部类上增加相应的static函数,以访问外部类的相应私有成员。
如果不希望内部类引用外部类,则可以将其声明为static的。
9.4 方法内部类
可以在方法中定义内部类。方法中的内部类,可以访问外部方法的final类型的常量局部变量。
编译器的实现更为简单,将内部类所引用的外部局部变量作为构造器参数复制给类,并作为其成员。
9.5 匿名内部类
如果类只使用一次,则可以创建为匿名的。使用语法为:
Type val = new SuperType(cons paras) { //内部类的方法及数据定义 }
匿名内部类如果过长,会不利于代码的理解,应该限制使用。
示例:
public class TimerTest { public static void main(String[] args) { Timer t = new Timer(); // class myTask extends TimerTask // { // public void run() // { // System.out.printf("Runing at %s \n",new Date()); // } // } // TimerTask task = new myTask(); TimerTask task = new TimerTask() { public void run() { System.out.printf("Runing at %s \n",new Date()); } }; t.schedule(task, 0, 1000); try { Thread.sleep(10000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } t.cancel(); } }
10 反射代理
代理是一种支持在运行时创建支持特定接口的类对象的方法,类的代码可以通过类加载器从远程或本地进行加载。
Object Proxy.newProxyInstance(ClassLoader cl,Class[] interfaces,InvocationHandler ih)
Object invoke(Object proxy,Method method,Object[] args)
而被代理的对象,则通过实现InvocationHandler接口的invoke()方法将对象进行包装。
这里有个要求,就是被代理的类需要实现了特定的接口,如果一个类不是实现自接口,则无法这样使用。
import java.lang.reflect.*; import java.util.Arrays; public class ProxyTest { public static void main(String[] args) { Object[] elements = new Object[1000]; for(int i = 1;i<elements.length;i++) { Integer value = i ; Class[] interfaces = value.getClass().getInterfaces(); InvocationHandler handler = new TracekHandler(value); Object proxy = Proxy.newProxyInstance(null, interfaces, handler); elements[i] = proxy; } int result = Arrays.binarySearch(elements, 300); if(result>=0) { System.out.println(elements[result]); } } } class TracekHandler implements InvocationHandler { public TracekHandler(Object target) { this.target = target; } public Object invoke(Object proxy,Method m,Object[] args) throws Exception { System.out.print(target); System.out.print("."+m.getName()+"("); if(args!=null) { } System.out.println(")"); return m.invoke(target, args); } private Object target; }
相关文章推荐
- java基础(2)-基础类型和语法(static、内部类、final、抽象类、接口、封装)(并将这些基础知识与java的三大特征关联(继承、多态、封装))
- JAVA 构造器, extends[继承], implements[实现], Interface[接口], reflect[反射], clone[克隆], final, static, abstrac
- JAVA基础【6.2】《Java核心技术1》接口与内部类-对象克隆
- 学习笔记——Java核心技术之接口、继承与多态练习题
- JAVA基础【6.3】《Java核心技术1》接口与内部类-回调
- All About JAVA 继承、多态、抽象类、接口、面向接口编程
- 黑马程序员——java-面向对象二(继承,多态,抽象,接口,包,内部类)
- 【笔记】Java编程思想—一接口与内部类
- java核心技术-接口和内部类(1)
- JAVA基础【6.4】《Java核心技术1》接口与内部类-内部类
- C\C++ 程序员从零开始学习Android - 个人学习笔记(八) - java基础 - 继承、抽象类、接口、内部类(待续)
- 黑马程序员 Java面向对象(继承,抽象类,接口,多态,内部类)
- Java基础-->面向对象<继承,内部类,多态,包,抽象与接口>
- JAVA基础【6.5】《Java核心技术1》接口与内部类-代理
- java 继承 多态 虚拟类 接口 异常 线程 内部类
- java核心技术笔记 接口与内部类
- Java学习笔记-对象-继承-接口-多态-内部类
- C\C++ 程序员从零开始学习Android - 个人学习笔记(八) - java基础 - 继承、抽象类、接口、内部类(待续)
- 匿名内部类是否可以继承其它类是否可以实现接口 _JAVA面试题及答案
- JAVA 内部类、外部类、继承、抽象类、接口实战