查看“核心技术:继承”的源代码
←
核心技术:继承
跳到导航
跳到搜索
因为以下原因,您没有权限编辑本页:
您请求的操作仅限属于该用户组的用户执行:
用户
您可以查看和复制此页面的源代码。
[[category:JavaCore]] == 类、超类和子类 == === 定义子类 === 关键字 extends 表示正在构造的新类(subclass子类;derived class派生类;child class孩子类)派生于一个已存在的类(superclass超类、base class基类、parent class父类) === 覆盖方法 === 父类中的某些方法对子类并不一定适应,需要子类对方法覆盖(override); * 子类不能之间访问父类的私有域,必须使用父类私有域对应的公有访问接口; * 子类可以增加域、增加方法、覆盖方法,但不能删除继承的域和方法; * 覆盖一个方法的时候,子类方法不能低于超类方法的可见性; “super”关键字用于只是编译器调用父类方法。 * super与this不同,并非一个对象的引用,不能将super赋给另一个对象变量; === 子类构造器 === 子类构造器中: * 如果使用super显示调用父类构造器,则该语句必须是子类构造器的第一条语句出现; * 如果没有显示调用父类构造器,则将自动地调用父类默认(没有参数)的构造器; * 如果没有显示调用父类构造器,且父类没有无参构造器,则Java编译器将报告错误; === 多态 === 有一个用来判断是否应该设计为继承关系的规则:“is-a”,即“'''置换法则'''”,'''程序中出现超类对象的任何地方都可以用子类对象置换'''。 * 一个对象可以指示多种实际类型的现象,被称为'''多态'''(polymorphism);<br/> *: 如,Employee既可以引用一个Employee对象,也可以引用Employee的子类对象(如,Manager) * 在运行时能自动地选择调用哪个方法的现象,被称为'''动态绑定'''(dynamic binding);<br/> * 如果方法是private方法、static方法、final方法,那么编译器可以准确地知道应该调用的方法,这种调用方式被称为'''静态调用'''(static bingding); === 阻止继承:final类和方法 === final使用: * final域:域不能被修改 * final方法:方法不能被覆盖 * final类:类不能被扩展(即不能被继承) *: 类中的所有方法自动成为final *: 类中的域并不为final === 强制类型转换 === 对象的强制类型转换: # 只能在继承层次内进行类型转换; # 在将父类转换为子类之前,应该用'''instanceof'''检查 #* “instanceof”用于判断对象是否为某个类型 === 抽象类 === * 包含一个或多个抽象方法的类,必须被声明为抽象类; * 除了抽象方法,抽象类还可以包含具体数据和具体方法; * 抽象类不能被实例化; * 可以定义抽象类对象,该对象只能引用非抽象子类的对象; === 受保护访问 === # public:公有,对其他类可见 # private:私有,对其他类不可见(即使子类也不可见) # protect:受保护,对所有子类 及同一个包中的其他类可见,包外不可见 * 对本包可见是默认的,不需要修饰符; == Object:所有类的超类 == Object 类Java中所有类的始祖,每个类都由它扩展而来 * 只有基本类型不是对象 * 所有的数组类型(无论基本类型数组,对象数组),都扩展了Object类 === equals === 用于判断一个对象是否等于另一个对象。(需要重写) * 在Object中,equals将判断两个对象的是否有相同的引用(与“==”一样); * 为了判断值相等,应该重写equals方法,进行内容判断(先比较hashcode,再比较值); ==== 相等测试与继承 ==== Java语言规范要求equals方法具有以下特性: # 自反性:对于任何非空引用x,均有x.equals(x)=true; # 对称性:对于任何引用x、y,当且仅当x.equals(y)=true,则应y.equals(x)=true; # 传递性:对于任何引用x、y、z,如果x.equals(y)=true且y.equals(z)=true,则有x.equals(z)=true; # 一致性:如果x、y引用的对象没有变化,反复调用x.equals(y)应返回同样结果; # 对于任何非空引用x,均有x.equals(null)=false; === hashcode === 散列码(hashcode)是由对象导出的一个整型值,是没有规律的: # 两个不同对象的hashcode基本不会相同; # 两个对象相同,其hashcode必定相同(所以在equals前先比较hashcode可以提高效率); * “hashcode()”应该返回一个整型数值(可以负数),并合理地组合实例域的散列码,以便能让各个不同的对象产生的散列码更加均匀; * 最好使“hashcode()”对null安全:如果参数为null,这个方法返回0,否则返回对参数调用hashcode的结果; === toString === 该方法用于返回表示对象值的字符串。(需要重写) == 泛型数组列表 == ArrayList使用: <syntaxhighlight lang="java"> ArrayList<E>() // 构造一个空数组列表 ArrayList<E>(int initialCapacity) //用指定容量构造一个空数组列表(initialCapacity:初始容量) boolena add(E obj) // 在数组列表的尾端添加一个元素 int size() // 返回存储在数组列表中的当前元素数量 void ensureCapacity(int capacity) // 确保数组列表在不重新分配存储空间的情况下,就能保存给定数量的元素 void trimToSize() // 将数组列表的存储容量削减到当前(使用的)尺寸 </syntaxhighlight> * 一旦整理了数组列表的大小,或者空间被完全使用,添加新元素时就需要再次移动存储块 === 访问数组列表元素 === <syntaxhighlight lang="java"> void set(int index, E obj) // 设置元素,将会覆盖原有内容 E get(int index) // void add(int index, E obj) // E remove(int index) // </syntaxhighlight> === 类型化与原始数组列表的兼容性 === == 对象包装器与自动装箱 == 所有的基本类型都有一个对应的类,即包装器(wrapper): #“Integer”、“Long”、“Float”、“Double”、“Short”、“Byte”、“Character”、“Void”、“Boolean”: # 前六个派生于公共超类“Number”; 关于 wrapper: * 对象包装器类是不可变的,即:一旦构造了包装器,就不允许更改包装在其中的值; * 同时,对象包装器类还是 final,因此不允许定义它们的子类; 使用: # 自动装箱:将基本类型赋给一个包装器对象时; # 自动拆箱:将一个包装器对象赋给基本类型时; * 拆箱装箱时编译器认可的,而不是虚拟机; * 自动装箱要求boolean、byte、char<=127、介于-128-127之间的short和int被包装到固定的对象中; * 如果在一个表达式中,混合使用Integer和Double:Integer会被拆箱为,提升为double,再装箱为Double; 另: <syntaxhighlight lang="java"> int x = Integer.parseInt(s); </syntaxhighlight> 可以将s强制转换为int类型(parse为静态方法) == 参数数量可变的方法 == 在 Java SE 5 之前的版本中,每个方法都有固定数量的参数。 <syntaxhighlight lang="java"> public class PrintStream { public PrintStream printf(String fmt, Object... args) { return format(fmt, args); } } </syntaxhighlight> 其中“Object... args”的省略号也是代码的一部分,表示这个方法可以接受任意数量的对象(除 fmt 参数外)。 # 对于printf的实现来说:“Object... args”与“Object[] args”完全一样; # 对于printf的调用来时:将以前args[]数组的元素,单个依次传递为为方法参数; * 允许将一个数组传递给可变参数方法的最后一个参数。 == 枚举类 == 如[http://wiki.eijux.com/%E6%A0%B8%E5%BF%83%E6%8A%80%E6%9C%AF%EF%BC%9A%E5%9F%BA%E6%9C%AC%E7%A8%8B%E5%BA%8F%E8%AE%BE%E8%AE%A1%E7%BB%93%E6%9E%84#.E6.9E.9A.E4.B8.BE.E7.B1.BB.E5.9E.8B]: <syntaxhighlight lang="java"> public enum Size{SMALL, MEDIUM, LARGE, EXTRA_LARGE}; </syntaxhighlight> 声明了一个枚举类(这是一个类!) # 所有枚举类都是“Enum”类的子类; # 比较两个枚举类型的值时,应该用“==”而非“equals”; # “toString”方法用于返回枚举常量名; # “toString”的逆方法为静态方法“valueOf”:用于获取枚举常量; == 反射 == 反射库(reflection library)提供了一个非常丰富且精心设计的工具集,以便能够动态操纵Java代码的程序。<br/> 能够分析类能力的程序成为'''反射'''(reflective),可以用作: # 在运行时分析类的能力; # 在运行时查看对象; # 实现通用的数组操作代码; # 利用“Method”对象,这个对象很像 C++ 中的函数指针; * 反射主要用在工具框架的构造过程中; === Class类 === <pre> 在程序运行期间,Java运行时系统始终为所有的对象维护一个被称作“运行时”的类型标识。 这个信息跟踪着每个对象所属的类。虚拟机利用运行时类型信息选择相应的方法执行。 然而,可以通过专门的Java类访问这些信息。保存这些新欻的类被称为“Class”。 如同一个Employee对象表示某个的雇员一样,一个Class对象将表示某个类的属性。 </pre> ==== 获取“Class类”对象 ==== # Java对象的“getClass()”方法:【普通对象的方法】 #: <syntaxhighlight lang="java" highlight="2"> Employee e = new Employee(); Class c1 = e.getClass(); System.out.println(c1.getName()); // 结果:Employee </syntaxhighlight> #: 如果类在包里,则包名也作为类名的一部分,如“java.util.Random” # “Class”类的静态方法“forName()”:【Class类的静态方法】 #: <syntaxhighlight lang="java" highlight="2"> String className = "java.util.Random"; Class c2 = Class.forName(className); System.out.println(c2.getName()); // 结果:Random </syntaxhighlight> #: 只有在className时类名或接口名时才能执行,否则抛出“checked exception” #: 无论何时使用此方法,都应该提供一个异常处理器(exception handler) # “Java类名.class”【类字面量】 #: <syntaxhighlight lang="java" highlight="1,5,9"> Class c3 = Employee.class; System.out.println(c3.getName()); // 结果:Employee // 运用.calss的方式获取Class实例(基本类型) Class c4 = Random.class; System.out.println(c4.getName()); // 结果:int // 运用.class的方式获取Class实例(基本数据类型的封装类) Class c5 = Integer.TYPE; System.out.println(c5.getName()); // 结果:int </syntaxhighlight> * 一个“Class”对象实际上表示的时一个类型,而这个类型未必一定是一种类; *: 如:int不是一个类,但int.Class是一个Class类型的对象; * Class类 实际上是一个泛型类,如:“Employee.class”的类型是“Class<Employee>” * 虚拟机为每个类型管理一个Class对象,因此可以利用“==”实现两个类对象的比较: *: <syntaxhighlight lang="java"> if(e.getClass() == Employee.class) </syntaxhighlight> ==== 创建类的实例 ==== “newInstance()”方法用于动态地创建一个类的实例: <syntaxhighlight lang="java"> e.getClass().newInstance(); // e 是一个Employee对象 </syntaxhighlight> * 将 forName 与 newInstance 配合使用,可以根据存储在字符串中的类名创建一个对象: *: <syntaxhighlight lang="java"> String s = "java.util.Random"; Object m = Class.forName(s).newInstance(); </syntaxhighlight> * newInstance方法调用默认的构造器(无参构造器)来初始化新创建的对象,如果这个类没有默认的构造器,则会抛出异常。 === 利用反射分析类的能力 === <pre> 在“java.lang.reflect”包中有三个类“Field”、“Method”和“Constructor”分别用于描述类的域、方法和构造器。 这三个类都有一个叫做“getName”的方法,用来返回项目的名称。 Field类有一个“getType”方法,用来返回描述域所属类型的Class对象。 Method 和Constructor 类有能够报告参数类型的方法,Method 类还有一个可以报告返回类型的方法。 这三个类还有一个叫做“getModifiers”的方法,它将返回一个整型数值,用不同的位开关描述public 和static 这样的修饰符使用状况。 另外,还可以利用“java.lang.reflect”包中的“Modifier”类的静态方法分析“getModifiers”返回的整型数值。 例如,可以使用Modifier 类中的“isPublic”、“isPrivate”或“isFinal”判断方法或构造器是否是public、private 或final。 Class 类中的“getFields”、“getMethods”和“getConstructors”方法将分别返回类提供的 public域、方法和构造器数组,其中包括超类的公有成员。 Class 类的“getDeclareFields”、“getDeclareMethods”和“getDeclaredConstructors”方法将分别返回类中声明的全部域、方法和构造器,其中包括私有和受保护成员,但不包括超类的成员。 </pre> ==== java.lang.Class ==== # Field[] getFields() 1.1 # Filed[] getDeclaredFie1ds() 1.1 #: getFields 方法将返回一个包含 Field 对象的数组,这些对象记录了这个类或其超类的公有域。getDeclaredField 方法也将返回包含 Field 对象的数组, 这些对象记录了这个类的全部域。如果类中没有域,或者Class 对象描述的是基本类型或数组类型,这些方法将返回一个长度为0 的数组。 # Method[] getMethods() 1.1 # Method[] getDeclareMethods() 1.1 #: 返回包含Method 对象的数组:getMethods 将返回所有的公有方法,包括从超类继承来的公有方法;getDeclaredMethods 返回这个类或接口的全部方法, 但不包括由超类继承了的方法。 # Constructor[] getConstructors() 1.1 # Constructor[] getDeclaredConstructors() 1.1 #: 返回包含Constructor 对象的数组, 其中包含了Class 对象所描述的类的所有公有构造器(getConstructors ) 或所有构造器(getDeclaredConstructors)。 ==== java.lang.reflect.Field ==== ==== java.lang.reflect.Method ==== ==== java.lang.reflect.Constructor ==== # Class getDeclaringClass() #: 返冋一个用于描述类中定义的构造器、方法或域的Class 对象。 # Class[] getExceptionTypes() ( 在Constructor 和Method 类中) #: 返回一个用于描述方法抛出的异常类型的Class 对象数组。 # int getModifiers() 返回一个用于描述构造器、方法或域的修饰符的整型数值。使用Modifier 类中的这个方法可以分析这个返回值。 # String getName() #: 返冋一个用于描述构造器、方法或域名的字符串。 # Class[] getParameterTypes() ( 在Constructor 和Method 类中) #: 返回一个用于描述参数类型的Class 对象数组。 # Class getReturnType() ( 在Method 类中) #: 返回一个用于描述返H类型的Class 对象。 ==== java.lang.reflect.Modifier ==== # static String toString( int modifiers ) #: 返回对应modifiers中位设置的修饰符的字符串表示。 # static boolean isAbstract ( int modifiers ) # static boolean isFinal ( int modifiers ) # static boolean islnterface( int modifiers ) # static boolean isNative( int modifiers ) # static boolean isPrivate( int modifiers ) # static boolean isProtected( int modifiers ) # static boolean isPublic( int modifiers ) # static boolean isStatic( int modifiers ) # static boolean isStrict( int modifiers ) # static boolean isSynchronized( int modifiers ) # static boolean isVolati 1e( int modifiers ) 这些方法将检测方法名中对应的修饰符在modffiers 值中的位。 === 在运行时使用反射分析对象 === ==== java.lang.reflect.AccessibleObject ==== # void setAccessible(boolean flag) #: 为反射对象设置可访问标志。flag 为true 表明屏蔽Java 语言的访问检查,使得对象的私有属性也可以被査询和设置。 # boolean isAccessible( ) #: 返回反射对象的可访问标志的值。 # static void setAccessible(AccessibleObject[ ] array,boolean flag) #: 是一种设置对象数组可访问标志的快捷方法。 ==== java.lang.Class ==== # Field getField( String name ) # Field[ ] getFieldO #: 返回指定名称的公有域, 或包含所有域的数组 # Field getDeclaredField( String name ) # Field[ ] getDeclaredFields( ) #: 返回类中声明的给定名称的域, 或者包含声明的全部域的数组。 ==== java.lang.reflect.Field ==== # Object get(Object obj ) #: 返回obj 对象中用Field 对象表示的域值。 # void set(Object obj ,Object newValue) #: 用一个新值设置Obj 对象中Field 对象表示的域。 === 使用反射编写泛型数组代码 === === 调用任意方法 === == 继承的设计技巧 ==
返回至“
核心技术:继承
”。
导航菜单
个人工具
登录
命名空间
页面
讨论
大陆简体
已展开
已折叠
查看
阅读
查看源代码
查看历史
更多
已展开
已折叠
搜索
导航
首页
最近更改
随机页面
MediaWiki帮助
笔记
服务器
数据库
后端
前端
工具
《To do list》
日常
阅读
电影
摄影
其他
Software
Windows
WIKIOE
所有分类
所有页面
侧边栏
站点日志
工具
链入页面
相关更改
特殊页面
页面信息