长沙网站公司,wordpress api 小程序,重庆建设工程安全信息管理网,注册外贸公司的流程及费用5继承
5.1 类、超类和子类
关键字extends表示继承。
Java中的继承都是公用继承#xff0c;没有C中的私有继承和保护继承。 Super class Subclass 来自于集合的术语
Base class Derived class
Parent class Child class 将通用的功能放在超类中#xff0c;将具有特…5继承
5.1 类、超类和子类
关键字extends表示继承。
Java中的继承都是公用继承没有C中的私有继承和保护继承。 Super class Subclass 来自于集合的术语
Base class Derived class
Parent class Child class 将通用的功能放在超类中将具有特殊用途的方法放在子类中。 子类中可以覆盖override超类中的方法。
子类不能直接访问超类的私有域。
子类中调用超类方法super.method()
C中用 [超类名::方法]的方式调用超类方法。 因为子类不能访问超类私有域
子类的构造器中第一条语句要用super(...)调用超类构造器
如果未提供super()语句则调用默认无参数的超类构造器
如果超类没有默认构造器则编译出错。 C中利用初始化列表语法调用超类构造器。 继承层次
由一个公共超类派生出来的所有类的集合被称为继承层次inheritance hierarchy。
从某个特定的类到其祖先的路径被称为该类的继承链inheritance chain。
一个祖先类可以拥有多个子孙继承链。
Java不支持多继承。 多态
IS-A规则子类的每个对象也是超类的对象。
即置换法则程序中出现超类对象的任何地方都可以用子类对象置换。
超类对象变量可以引用任何其子类对象。
不能将超类的引用赋给子类变量。 静态绑定 static binding
对于private方法、static方法、final方法或者构造器编译器可明确知道应该调用哪个方法。
动态绑定
调用的方法依赖于隐式参数的实际类型并且在运行时实现动态绑定。
虚拟机预先为每个类创建一个方法表method table其中列出了所有方法的签名和实际调用的方法。真正调用的时候虚拟机查找这个表。 覆盖一个方法时子类方法不能低于超类方法的可见性。 阻止继承
Final类不允许被扩展的类。
Final方法不允许被重写的方法。
Final类中的方法自动的称为final方法。
Final域常量。
Final的主要目的确保它们不会在子类中改变语义。
String类是final类。 如果一个方法没有被覆盖并且很短编译器进行内联inlining优化处理。因为分支转移会扰乱指令预取策略。 强制类型转换
用一对圆括号将目标类名括起来置于需要转换的目标引用之前。
唯一原因在暂时忽视对象的实际类型之后使用对象的全部功能。
可以将子类引用赋给超类变量但当超类引用赋给子类变量时必须进行类型转换。
在类型转换之前进行instanceof检查。
综上所述
1、只能在继承层次内进行类型转换
2、在将超类转换成子类之前使用instanceof进行检查。 在一般情况下应该尽量少用类型转换和instanceof运算符。 C的类型转换Manager* boss dynamic_castManager*(staff[1]); 抽象类
包含一个或多个抽象方法的类必须声明为抽象类。
抽象类可以包含具体数据和具体方法。 其子类如果实现部分抽象方法则也需声明为抽象类
子类若实现全部抽象方法则不必声明为抽象方法。 类即使不包含抽象方法也可以将其声明为抽象类。
抽象类不能被实例化。
可以定义一个抽象类的对象变量但是只能引用非抽象子类的对象。 C中的抽象类只要包含纯虚函数的类就是抽象类。 编译器只允许调用在类中声明的方法。 受保护访问
允许子类的方法访问超类的某个域或希望超类的某些方法被子类访问。
protected
最好的示例Object类中的clone方法。 Private——对本类可见
Public——对所有类可见
Protected——对本包和所有子类可见
默认——对本包可见。 5.2 Object所有类的超类
Object类型的变量可以引用任何类型的对象。
在java中只有基本类型primitive types不是对象。
所有数组类型都是对象扩展于Object类。 equals方法 public boolean equals( Object other);
Object中检测两个对象变量是否有相同的引用功能与一致。
在子类定义equals方法时首先调用超类的equals方法。如果检测失败对象就不可能相等。如果超类中的域都相等就需要比较子类中的实例域。 Java要求equals语法具有下面的性质
自反性
对称性
传递性
一致性
X.equals(null)应该返回false 重写符号方法前一行加override 重写equals方法步骤
1、显式参数命名为otherObject
2、检测this与otherObject是否引用同一个对象if (this otherObject) return true;
3、检测otherObject是否为空if (otherObject null) return false;
4、检测otherObject是否属于同一类。
a) 如果equals的语义在每个子类中有所改变用getClass检测
if (getClass() ! otherObject.getClass()) return false;
b) 如果所有的子类都拥有统一语义就使用instanceof检测
if (!(otherObject instanceof ClassName)) return false;
5、将otherObject转换为相应的类类型变量ClassName other (ClassName) otherObject;
6、对所有需要比较的域进行比较。需在其中包含调用super.equals(other); 数组类型的域用Arrays.equals(a1, a2)检查是否相等。 hashcode方法
public int hashcode();
定义在Object类中每个对象都有一个默认的散列码其值为对象的存储地址。
Equals方法必须和hashcode方法一致即如果a.equals(b)为真则a和b的散列码必须相同。 Objects.hashCode(Object a); //如果为Null返回0否则返回a.hashcode()
Objects.hash(Object... objects); //返回所有对象的散列码组合。 数组类型的域用Arrays.hashCode(a)计算散列码。 toString方法
Object类定义了toString()方法打印输出对象所属的类名和散列码。
绝大多数遵循格式类的名字[域值]
用getClass().getName()获得类的名字。
只要对象与字符串通过 相连就自动调用对象的toString()方法。
System.out.println(x); //自动调用x的toString()方法。 数组继承了object类的toString方法。
如果想打印数组的内容用Arrays.toString(a)多维数组用Arrays.deepToString(a) 强烈建议为自定义的每一个类增加toString方法。 SuppressWarnings(“unchecked”) 包装器wrapper 自动装箱autoboxing 自动拆箱 5.3 参数数量可变方法
最后一个参数为 类名... args实际传入一个数组。调用时可以传入多个类对象甚至一个类数组。 5.4 枚举类
所有枚举类型都是Enum类的子类。
比较时直接用“” 5.6 反射
反射库reflection library提供了一个非常丰富且精心设计的工具集以便编写能够动态操纵java代码的程序。这项功能被大量地应用于JavaBeans中它是Java组件的体系结构。
能够分析类能力的程序称为反射reflective。 在程序运行期间系统保存了所有已加载类的信息虚拟机用这些信息选择相应的方法执行。
保存这些信息的类被称为Class。 获得类对象的三种方法
1、Object类中的getClass()方法将会返回一个Class类型的实例。
2、还可以通过调用静态方法forName获得类名对应的Class对象。
String className “java.util.Date”;
Class c1 Class.forName(className);
当包含main()方法的类被加载时将会递归加载全部所需类。
一种逐步加载方法调用Class.forName()手工加载其他类。
3、Class cl1 Data.class; 可以利用运算符实现两个类对象的比较操作。 类对象的newInstance()方法可以快速创建一个类的实例调用的是默认构造函数。
String s “java.util.Date”;
Object m Class.forName(s).newInstance(); 利用反射分析类的能力
反射机制最重要的内容——检查类的结构。
在java.lang.reflect包中用三个类Field、Method、Constructor分别用于描述类的域、方法和构造函数。
Class类中的getFileds()、getMethods()、getConstructors()将返回public域、方法、构造器数组包括超类的公有成员。
Class类中的getDeclareFiels()、getDeclaredMehtods()、getDeclaredConstructors()返回全部域、方法、构造器数组不包括超类的公有成员。 public class ReflectionTest
{public static void main(String[] args){String name;Scanner in new Scanner(System.in);System.out.print(Enter class name: );name in.next();StringBuilder sb new StringBuilder();try{Class c1 Class.forName(name);Class superc1 c1.getSuperclass();String modifiers Modifier.toString(c1.getModifiers());if ( modifiers.length() 0 )sb.append(modifiers );sb.append(class name);if (superc1 ! null superc1 ! Object.class)sb.append( extends superc1.getName());sb.append(\n{\n);Constructor[]constructors c1.getDeclaredConstructors();for (Constructor c : constructors){String cname c.getName();sb.append(\t);String cmodifier Modifier.toString(c.getModifiers());if (cmodifier.length() ! 0)sb.append(cmodifier );sb.append(cname();Class[]cparameters c.getParameterTypes();for ( int j 0; j cparameters.length; j){if (j 0)sb.append(,);sb.append(cparameters[j].getName());}sb.append();\n);}sb.append(\n\n);Method[]methods c1.getDeclaredMethods();for (Method m : methods){sb.append(\t);String mmodifier Modifier.toString(m.getModifiers());if (mmodifier.length() ! 0)sb.append(mmodifier );String rtype m.getReturnType().getName();sb.append(rtype m.getName() ();Class[]mparameters m.getParameterTypes();for (int i 0; i mparameters.length; i){if (i 0)sb.append(,);sb.append(mparameters[i].getName());}sb.append()\n);}sb.append(\n\n);Field[]fields c1.getDeclaredFields();for (Field f : fields){sb.append(\t);String fmodifier Modifier.toString(f.getModifiers());if( fmodifier.length() !0 )sb.append(fmodifier );Class type f.getType();String tname type.getName();String fname f.getName();sb.append(tname fname ;\n);}sb.append(});System.out.println(sb);}catch(ClassNotFoundException e){e.printStackTrace();}}
}利用反射机制查看域值
f.setAcessible(true);
f.get(obj);
利用反射机制修改域值
f.get(obj, value); 编写一个可供任意类使用的通用toString方法
1、使用getDeclaredFileds获得所有数据域
2、使用setAccessible将所有的域设置为可访问的
3、对每个域获得名字和值。 setAccessible方法是AccessibleObject类中的一个方法是Filed、Method、Constructor类的公共超类。 Method对象的invoke方法允许调用包装在当前Method对象中的方法。
方法签名
Object invoke(Object obj, Object... args);
第一个参数为具体对象其余为这个方法的参数。
对于静态方法第一个参数设置为NULL。
Invoke的参数和返回值必须是Object类型的。
使用反射获得方法指针的代码要比仅仅直接调用方法明显慢一些。 5.7 继承设计的技巧
1、将公共操作和域放在超类
2、不要使用受保护的域
3、使用继承体现IS-A关系
4、除非所有继承的方法都有意义否则不要使用继承
5、在覆盖原方法时不要改变预期的行为
6、使用多态
7、不要过多的使用反射——对编写系统程序及其有用不适用于应用程序的编写。