【JAVA核心技术卷一】Inheritance 继承

来源:互联网 发布:java窗口程序 编辑:程序博客网 时间:2024/06/05 06:37

Inheritance 继承

  • 继承
  • 强制类型转换
  • 抽象类
  • Object类
  • 对象包装器与自动装箱
  • 枚举
  • 反射

关键字 extends表示继承,表明正在构造的新类派生于一个已存在的类

已存在的类称为:

    超类(superclass)、基类(basicclass)、父类(parent class

新类称为:

           子类(subclass)、派生类(derivedclass)、孩子类(child class)

在Java中,所有的继承都是公有继承,而没有C++里的私有继承和保护继承

在通过扩展超类定义子类的时候,仅需要指出子类与超类的不同之处。**因此在设计类的时候,应该将通用的方法放在超类,而将具有特殊用途的方法放在子类中。这种将通用功能放到超类的做法,在面向对象程序设计中十分普遍。**

       在子类中可以增加域、增加方法或者覆盖超类的方法,然而绝对不能删

除继承的任何域和方法。

强制类型转换

  • 只能在继承层次内进行类型转换

  • 在将超类转换成子类之前,应该使用instanceof进行检查

    Manager boss = (Manager) staff[1];

    等价于

    if( staff[1] instanceof Manager){                   Manager boss= (Manager) staff[1];           }

在一般情况下,应该尽量少用类型转换和instanceof运算符

抽象类

  • 包含一个或多个抽象方法的类本身必须被声明为抽象的

  • 除了抽象方法之外,抽象类还可以包含具体数据和具体方法

  • 类即使不含抽象方法,也可以将类声明为抽象类

Object类

Object类是Java中所有类的超类。如果没有明确地指出超类,Object就被认为是这个类的超类。

可以用Object类型的变量引用任何类型的对象

Object obj = new Employee("Peter", 2000);

想要对其中的内容进行具体的操作,还需要清楚对象的原始类型,并进行相应的类型转换:

Employee e = (Employee)obj;

在Java中,只有基本类型(primitive types)不是对象。例如,数值、字符和布尔类型的值都不是对象。所有的数组类型,不管是对象数组还是基本类型的数组都扩展于Object类。

equals方法

Object类中的equals方法用于检测一个对象是否等于另外一个对象。在Object类中,这个方法将判断两个对象是否具有相同的引用。

**如果对比的两个参数都为nullObject.equals(a,b)的调用将返回true。**

hashCode方法

散列码(hash code)是由对象导出的一个整型值。散列码是没有规律的。

由于hashCode方法定义在Object类中,因此每个对象都有一个默认的散列码,其值为对象的储存地址

public int hashCode(){  return Object.hashCode(name , salary ,hireday);}

Equals与hashCode的定义必须一致:如果x.equals(y)返回true,那么x.hashCode()就必须与y.hashCode()具有相同的值。


toString方法

如果x是任意一个对象,并调用

System.out.println(x);

println方法就会直接调用x.toString(),并打印输出得到的字符串。

Object类定义了toString方法,用来打印输出对象所属的类名和散列码(十六进制),也可以通过

x.getClass().getName()+x.hashCode()//注意这里得到的x.hashCode()为十进制

对象包装器与自动装箱

  • 对象包装器

有时候需要将int这样的基本类型转换为对象。所有的基本类型都有一个与之对应的类。例如,Integer类对象基本类型int。通常,这些类称为包装器(wrapper)

这些对象包装器类分为:

IntegerLongFloatDoubleShortByteCharacterVoidBoolean(前6个类派生于公共的超类Number

对象包装器是不可变的,即一旦构造了包装器,就不允许更改包装在其中的值。同时,对象包装器还是final,因此不能定义它们的子类

假设想定义一个整型数组列表。而尖括号中的类型参数不允许是基本类型,也就是说,不允许写成`ArrayList<int>`。这里就用到了`Integer`对象包装器类。我们可以声明一个`Integer`对象的数组列表
ArrayList<Integer> list = new ArrayList();

!警告:由于每个值分别包装在对象中,所有ArrayList<Integer>的效率远远低于int[]数组。因此,应该用于小型集合,其原因是此时程序员操作的方便性要比执行效率更加重要


  • 自动装箱

下面这个调用:

list.add(3);

将自动变换成:

list.add(Integer.valueOf(3));

这种变换被称为自动装箱(autoboxing)

相反的,当将一个Integer对象赋给一个int值时,将会自动地拆箱。

int n = list.get(i);

被编译器翻译成:

int n = list.get(i).intValue();

自动装箱规范要求booleanbytechar<=127、介于-128~127的shortint被包装到固定的对象中

装箱和拆箱是编译器认可的,而不是虚拟机。

枚举类

定义枚举类

public enum Size{    SMALL , MEDIUM , LARGE , EXTRA_LARGE};

其中toString方法能够返回枚举常量名

System.out.println(Size.SMALL.toString());> SMALL

toString的逆方法是静态方法valueOf

Size s = Enum.valueOf(Size.class , "SMALL");

s设置成Size.SMALL

每个枚举类型都有一个静态的values方法,它将返回一个包含全部枚举值的数组

Size[] x = Size.values();

返回包含元素Size.SMALLSize.MEDIUMSize.LARGESize.EXTRA_LARGE的数组

反射

能够分析类能力的程序成为反射(reflective)

反射机制的功能极为强大,其可以用来:

  • 在运行中分析类的能力
  • 在运行中查看对象,例如,编写一个toString方法供所有类使用
  • 实现通用的数组操作代码
  • 利用Method对象,这个对象很像C++中的函数指针

Class类

在程序运行期间,Java运行时系统始终为所有的对象维护一个被成为运行时的类型标识,这个信息跟踪着每个对象所属的类。

保存这些信息的类被称为Class类。Object类中的getClass()方法会返回一个Class类型的实例

Employee e;Class cl = e.getClass();

一个Class对象将表示一个特定类的属性。最常用的Class方法是getName()。这个方法会返回类的名字

System.out.prinltln(e.getClass().getName());> Employee

如果一个类在一个包里,包的名字也作为类名的一部分

import java.util.*;Date d = new Date();Class cl = d.getClass();System.out.println(cl.getName());> java.util.Date

还可以调用静态方法获得类名对应的Class对象

String className = "java.util.Date";Class cl = Class.forName(className);

Class.forName()返回值为一个类,其作用是要求JVM查找并加载指定的类,也就是说JVM会执行该类的静态代码段

如果类名保存在字符串中,并可以在运行中改变,就可以使用这个方法。当然,这个方法只有在className是类名或接口名时才能够执行。否则,forName方法将抛出一个checkedException。无论何时使用这个方法,都应该提供一个异常处理器(exception handler)

如果T是任意的Java类型,T.class将代表匹配的类对象

Class cl1 = Date.class;Class cl2 = int.class;Class cl3 = Double[].class;

注意:一个Class对象实际上表示的是一个类型,而这个类型未必一定是一种类。例如,int不是类,但int.Class是一个Class类型的参数

!警告:由于历史原因,getName在应用于数组类型是会返回一个奇怪的值

System.out.println(Double[].class.getName());>[Ljava.lang.DoubleSystem.out.println(int[].class.getName());>[L
  • newInstance()方法

newInstance()方法可以快速创建一个类的实例

e.getClass().newInstance();

关键字new相比,前者使用类加载机制,后者是创建一个新类。

从JVM的角度看,我们使用关键字new创建一个类的时候,这个类可以没有被加载。但是使用newInstance()方法的时候,就必须保证:

1、这个类已经加载;

2、这个类已经连接了

java工厂模式中经常使用newInstance()创建对象,例如

String className = Example;Class c = Class.forName(className);factory = (ExampleInterface)c.newInstance();

其中ExampleInterfaceExample的接口

现在可以看出,newInstance()实际上是把new这个方式分解为两步,即首先调用Class加载方法加载某个类,然后实例化。 这样分步的好处是显而易见的。我们可以在调用class的静态加载方法forName时获得更好的灵活性,提供给了一种降耦的手段。

分析类的能力

java.lang.reflect包中有三个类,FieldMethodConstructor分别用于描述类的域、方法和构造器,其都有getName方法

Field类有一个getType方法,用来返回描述域所属类型的Class对象

MethodConstructor类有能够报告参数类型的方法

这三个类还有一个叫做getModifiers的方法,它将返回一个整型数值,用不同的位开关描述publicstatic这样的修饰符使用状况

可以利用java.lang.reflect包中的Modifier类的静态方法分析getModifiters返回的整型数值。

例如:

可以使用`Modifier`类中的`isPublic`、`isPrivate`或`isFinal`判断方法或构造器是否是`public`、`private`或`final`。我们需要做的全部工作就是调用`Modifier`类的相应方法,并对返回的整型数值进行分析,另外,还可以利用`Modifier.toString`方法将修饰符打印出来。

例子:

import java.util.*;import java.lang.reflect.*;public class Hello{    public static void main(String[]args){        //read class name from command line args or user input        String name;        if(args.length>0){            name = args[0];        }else{            System.out.println("please input a class name : ");            Scanner in = new Scanner(System.in);            name  = in.next();        }        try{            Class cl = Class.forName(name);            Class supercl = cl.getSuperclass();            String modifiers = Modifier.toString(cl.getModifiers());            if(modifiers.length()>0){                System.out.println("modifiers: "+modifiers+" ");            }            System.out.println("class "+name);            if(supercl!=null&&supercl!=Object.class){                System.out.println("superClass :"+supercl.getName());            }            System.out.println();            printConstructors(cl);            System.out.println();            System.out.println();            printMethods(cl);            System.out.println();            System.out.println();            printFields(cl);            System.out.println();            System.out.println();        }catch(ClassNotFoundException e){            e.printStackTrace();        }    }   /**    * print all constructors of a class    * @param cl a class    */    public static void printConstructors(Class cl){        System.out.println("constructors");        Constructor[] constructors = cl.getDeclaredConstructors();        for(Constructor c :constructors){            String name = c.getName();            System.out.print("  ");            String modifiers = Modifier.toString(c.getModifiers());            if(modifiers.length()>0){                System.out.println("modifiers: "+modifiers+" ");            }            System.out.print(name + " ( ");            //print parameter types            Class[] paramTypes = c.getParameterTypes();            for(int j = 0;j<paramTypes.length;j++){                if(j>0){                    System.out.print(" , ");                }                System.out.print(paramTypes[j].getName());            }            System.out.print(" ) ");        }    }   /**    * print all methods of a class    * @param cl a class    */    public static void printMethods(Class cl){                System.out.println("Methods");        Method[] methods = cl.getDeclaredMethods();        for(Method m : methods){            Class retType = m.getReturnType();            String name = m.getName();            System.out.print("   ");            //print modifiers , return type and method name            String modifiers = Modifier.toString(m.getModifiers());            if(modifiers.length()>0){                System.out.println("modifiers: "+modifiers+" ");            }            System.out.print(retType.getName()+"  "+name + " ( ");            //print parameter types            Class[] paramTypes = m.getParameterTypes();            for(int j = 0;j<paramTypes.length;j++){                if(j>0){                    System.out.print(" , ");                }                System.out.print(paramTypes[j].getName());            }            System.out.print(" ) ");        }    }   /**    * print all fields of a class    * @param cl a class    */    public static void printFields(Class cl){        System.out.println("Fields");        Field[] fields = cl.getDeclaredFields();        for(Field f:fields){            Class type = f.getType();            String name = f.getName();            System.out.print("  ");            String modifiers = Modifier.toString(f.getModifiers());            if(modifiers.length()>0){                System.out.println("modifiers: "+modifiers+" ");            }            System.out.print(type.getName()+"  "+name + " ; ");        }    }}

当输入java.lang.Double时,console输出:

modifiers: public final class java.lang.DoublesuperClass :java.lang.Numberconstructors   modifiers: public java.lang.Double ( double )  ~ modifiers: public java.lang.Double ( java.lang.String ) Methods   modifiers: public boolean  equals ( java.lang.Object )    modifiers: public static java.lang.String  toString ( double )    modifiers: public java.lang.String  toString (  )    modifiers: public int  hashCode (  )    modifiers: public static int  hashCode ( double )    modifiers: public static double  min ( double , double )    modifiers: public static double  max ( double , double )    modifiers: public static native long  doubleToRawLongBits ( double )    modifiers: public static long  doubleToLongBits ( double )    modifiers: public static native double  longBitsToDouble ( long )    modifiers: public volatile int  compareTo ( java.lang.Object )    modifiers: public int  compareTo ( java.lang.Double )    modifiers: public byte  byteValue (  )    modifiers: public short  shortValue (  )    modifiers: public int  intValue (  )    modifiers: public long  longValue (  )    modifiers: public float  floatValue (  )    modifiers: public double  doubleValue (  )    modifiers: public static java.lang.Double  valueOf ( java.lang.String )    modifiers: public static java.lang.Double  valueOf ( double )    modifiers: public static java.lang.String  toHexString ( double )    modifiers: public static int  compare ( double , double )    modifiers: public static boolean  isNaN ( double )    modifiers: public boolean  isNaN (  )    modifiers: public static boolean  isInfinite ( double )    modifiers: public boolean  isInfinite (  )    modifiers: public static boolean  isFinite ( double )    modifiers: public static double  sum ( double , double )    modifiers: public static double  parseDouble ( java.lang.String ) Fields  modifiers: public static final double  POSITIVE_INFINITY ;   modifiers: public static final double  NEGATIVE_INFINITY ;   modifiers: public static final double  NaN ;   modifiers: public static final double  MAX_VALUE ;   modifiers: public static final double  MIN_NORMAL ;   modifiers: public static final double  MIN_VALUE ;   modifiers: public static final int  MAX_EXPONENT ;   modifiers: public static final int  MIN_EXPONENT ;   modifiers: public static final int  SIZE ;   modifiers: public static final int  BYTES ;   modifiers: public static final java.lang.Class  TYPE ;   modifiers: private final double  value ;   modifiers: private static final long  serialVersionUID ; 
0 0