文章目录
类、超类、和子类
在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());
}
}