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

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.Double

System.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.Double
superClass :java.lang.Number

constructors
   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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值