java 继承

类、超类、和子类

在java中,所有的继承都是公有继承,而没有c++中的私有继承和保护继承。

覆盖方法

在子类方法中可以用super.方法名()的形式来调用父类的方法。
super不是一个对象的引用,不能将值super赋给另一个对象变量,它只是一个指示编辑器调用超类方法的特殊关键字。

子类构造器

 public test(String name,double salary,int year,int month,int day)
    {
        super(name,salary,month,day);
        bonus=0;
    }

this有两个含义:一个指示隐式参数的引用,二是调用该类的其他构造器。类似的,super关键字也有两个含义,一个是调用超类方法,二是调用超类的构造器。
一个对象变量,可以指示多种实际类型的现象称为多态。在运行时能够自动地选择适当的方法,称为动态绑定。

继承层次

在java中不支持多重继承,但提供了一些类似多重继承的功能,例如接口。

多态

理解方法调用

强制类型转换

利用instanceof操作符来检查超类的引用是否是子类

if(staff[1]instanceof Manager)
        {
            boss=(Manager)staff[1];
        }
        Manager boss1=(Manager)staff[2];
  • 只能在继承层次内进行强制类型转换。
  • 在将超类强制转换成子类之前,应该使用instanceof进行检查。

如果x为null,进行一下测试
x instanceof C
也不会产生异常,只是返回false,因为null没有引用任何对象,当然也不会引用C类型的对象。

抽象类

包含一个或多个抽象方法的类本身必须被申明是抽象的。
除了抽象方法外,抽象类还可以包含字段和具体方法。

package chapter_5;

public abstract class Person {
    public abstract String getDescription();
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Person(String name) {
        this.name = name;
    }
}

抽象类不能实例化。也就是说把一个类声明为abstract,就不能创建这个类的对象。但可以创建一个具体子类的对象。
可以定义一个抽象类的对象变量,但是这样一个变量只能引用非抽象子类的对象。例如:

Person person=new Student("文天瑞");

受保护访问

protected:对本包和所有子类可见

Object

可以使用Object类型的变量引用任何类型的对象:
要想对其中内容进行具体操作,还需要清楚对象的原始数据类型例如:

   Object obj=new Student("文天瑞");
   Student s=(Student)obj;

所有的数组类型,不管是对象数组还是基本类型的数组都扩展了Object类。

equals方法

对于父类的equals定义

public boolean equals(Object otherObject)
    {
        if(this==otherObject) return true;
        if(otherObject==null) return false;
        if(getClass()!=otherObject.getClass())
            return false;
        Person other=(Person)otherObject;
        return Objects.equals(name,other.name);
    }
public boolean equals(Object otherObject)
    {
        if(!super.equals(otherObject)) return false;
        Student other=(Student)otherObject;
        return id==other.id;
    }

相等测试与继承

比较this和oterObject的类,如果equals的语义可以在子类中改变,就使用getclass检测

if(getClass()!=otherObject.getClass()) return false;

如果所有的子类都有相同的相等性语义,可以使用instanceof检测:
if(!(otherObject instanceof ClassName)) return false;

hashCode方法

两个内容相同的字符串有相同的散列码,但是字符串构造器却有着不同的散列码,因为StringBuilder类中没有定义hashCode方法,而Object类的默认hashCode方法会从对象地址得出散列码。

package chapter_5;

public class hashCOde {
    public static void main(String[] args) {
        var s="OK";
        var sb=new StringBuilder(s);
        System.out.println(s.hashCode()+" "+sb.hashCode());
        var t=new String("OK");
        var tb=new StringBuilder(t);
        System.out.println(t.hashCode()+" "+tb.hashCode());

    }
}

如果重新定义了equals方法,就很有必要为用户可能插入散列表的对象重新定义hashCode方法,因为当我们把对象存入到底层为散列表结构的集合时,首先判断hashCode值,碰到相同的hashCode值之后再进行equals()进一步判断,这样保证如果两个对象是相等的,它们的equals()方法应该返回true,hashCode()也应该返回相同的结果。

    遵守hashCode方法的常规约定。因为不能百分百确定这个类之后是否会在HashSet, Hashtable, HashMap等等这些本质是散列表的数据结构中用到,所以说重写equals()方法之后要尽量重写hashCode()方法。

注:hashCode方法的常规约定:

    在 Java 应用程序执行期间,在同一对象上多次调用 hashCode 方法时,必须一致地返回相同的整数,前提是对象上 equals 比较中所用的信息没有被修改。从某一应用程序的一次执行到同一应用程序的另一次执行,该整数无需保持一致。

    如果根据 equals(Object) 方法,两个对象是相等的,那么在两个对象中的每个对象上调用 hashCode 方法都必须生成相同的整数结果。

    以下情况不 是必需的:如果根据 equals(java.lang.Object) 方法,两个对象不相等,那么在两个对象中的任一对象上调用 hashCode 方法必定会生成不同的整数结果。但是,程序员应该知道,为不相等的对象生成不同整数结果可以提高哈希表的性能。

    实际上,由 Object 类定义的 hashCode 方法确实会针对不同的对象返回不同的整数。(这一般是通过将该对象的内部地址转换成一个整数来实现的,但是 JavaTM 编程语言不需要这种实现技巧。)

    当equals方法被重写时,通常有必要重写 hashCode 方法,以维护 hashCode 方法的常规协定,该协定声明相等对象必须具有相等的哈希码。

————————————————
版权声明:本文为CSDN博主「才疏学浅的小缘同学」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_44790505/article/details/123878587
例如:

public int hashCode() {
        return 7* Objects.hashCode(name)+11*Double.hashCode(salary)+13*Objects.hashCode(hireDay);
    }

当需要组合多个散列值时,可以调用Objects.hash例如:

 public int hashCode()
    {
        return Objects.hash(name,salary,hireDay);
    }

toString方法

一般都要为自己定义的类重写toString方法。

泛型数组列表

如果已经知道数组可能存储的元素数量,就可以在填充数组之前调用ensureCapacity方法:

staff.ensureCapacity(100);

另外还可以把初始容量传递给ArrayList构造器:

ArrayList<Employee>staff=new ArrayList(100);

容量为100但是数组列表不包含任何元素,例如:

package chapter_5;

import java.util.ArrayList;

public class ArrayList_test {
    public static void main(String[] args) {
        var staff=new ArrayList<polymorphic_my>(100);
        for (polymorphic_my polymorphic_my : staff) {
            System.out.println(polymorphic_my);
        }
        System.out.println("数组元素时100");
        var staff1=new polymorphic_my[10];
        for (polymorphic_my polymorphic_my : staff1) {
            System.out.println(polymorphic_my);
        }
    }
}

如果确定了数组列表的元素大小,就可以调用trimTosize;

package chapter_5;

import java.util.ArrayList;

public class ArrayList_test {
    public static void main(String[] args) {
        var staff=new ArrayList<polymorphic_my>(100);
        staff.add(new polymorphic_my("文天瑞",100,2003,5,12));
        staff.add(new polymorphic_my("谢雨晨",200,2000,6,12));
        for (int i = 0; i < staff.size(); i++) {
            System.out.println(staff.get(i));
        }
        System.out.println("数组的大小为"+staff.size());
        staff.trimToSize();
        System.out.println("数组的大小为"+staff.size());
    }
}

在c++中a=b会构造一个与b长度相同的新向量a,并将所有元素由b拷贝到a,但在java中,这条赋值语句的操作结果是让a和b引用同一个数组列表。

类型化和原始数组列表的兼容性

该如何与没有使用类型参数的遗留代码交互操作

package chapter_5;

import java.util.ArrayList;

public class ArrayList_test {
    public static void main(String[] args) {
        var staff=new ArrayList<polymorphic_my>(100);
        staff.add(new polymorphic_my("文天瑞",100,2003,5,12));
        staff.add(new polymorphic_my("谢雨晨",200,2000,6,12));
        for (int i = 0; i < staff.size(); i++) {
            System.out.println(staff.get(i));
        }
        System.out.println("数组的大小为"+staff.size());
        staff.trimToSize();
        System.out.println("数组的大小为"+staff.size());
    }
}

可以直接将staff对象传递给update方法;
相反,将一个原始ArrayList赋给一个类型化的ArrayList会得到一个警告

对象包装器和自动装箱

包装类是不变的,即一旦构造了包装类,就不允许更改包装在其中的值。

list.add(3);

将自动转化为

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

这种变换称为自动装箱。
相反地,将一个Integer对象赋给一个int值时,将会自动的拆箱。
自动装箱要求boolean,byte,char<=127,介于-128和127之间的short和int被包装到固定的对象中,例如,如果在前面的例子中将a和b初始化为100,那么他们的比较结果一定相等,例如:

  Integer a=100;
        Integer b=100;
        System.out.println(a==b);

结果会是true

 Integer a=128;
        Integer b=128;
        System.out.println(a==b);

只要不在范围内,结果就是false;
如果隐式参数的值为null,那么应该使用Objects.equals()方法来比较两者是否相等

Integer a=null;
        Integer b=null;
        System.out.println(Objects.equals(a,b));

可以将字符串变成数字,

 String s="123456";
       int x=Integer.parseInt(s);
        System.out.println(x);

还可以将整形变成字符串

 Integer a=1000;
       String s=a.toString();
        System.out.println(s);

参数可变的方法

printf是这样定义的:

    public PrintStream printf(String format, Object ... args) {
        return format(format, args);
    }

…是代码的一部分,它表明这个方法可以接受任意数量的对象(除fmt参数之外)。
允许将数组作为最后一个参数传递给可变参数的方法。例如

 System.out.printf("%d %s",new Object[]{new Integer(1),"widgets"});

如果愿意,可以将数组参数定义为有可变参数的方法。

枚举类

所有的枚举类型都是Enum的子类。

package chapter_5;

public enum Size {
    SMALL("S"),MEDIUM("M"),LARGE("L");
    private String abbreviation;
    private Size(String abbreviation){this.abbreviation=abbreviation;}
    public String getAbbreviation() {
        return abbreviation;
    }
    public static void main(String[] args) {
        System.out.println(Size.SMALL.toString());
        Size s=Enum.valueOf(Size.class,"SMALL");
        Size[]values=Size.values();
        for (Size value : values) {
            System.out.println(value.toString());
        }
        System.out.println(Size.MEDIUM.ordinal());
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值