引入经理与员工的故事。
超类与子类
- 使用extends关键词定义子类
public class Manager extends Employee
{
added methods and fields
}
在java中所有的继承都是公共继承(public),而没有私有继承。 原类称为超类、基类或者父类,新类称为子类、派生类
- 覆盖方法
当子类的某个方法与超类的某个方法意义相同,但是具体实现时由于子类的特性,代码中需要修改一些东西,这时候就出现覆盖方法的需求。 正确的代码覆盖方式
public double getSalary()
{
double baseSalary = super.getSalary();
return baseSalary + bonus;
}
注意其中super关键词的使用。覆盖方法子类方法不能低于超类方法的可见性。因为对于private类型来说,意思是只能被本类本身访问,但是super可以访问缺省类型的实例字段,具体可看如下
https://www.cnblogs.com/ffforward/p/15208333.html
- 子类构造器
public Manager(String name, double salary, int year, int month, int day)
{
super(name, salary, year, month, day);
bonus = 0;
}
其中super(name,salary,year,month,day)是在调用超类Employee中的参数构造器。如果不显示使用super语句,则默认调用超类的无参数构造器。如果显式调用,则必须放在第一句。
-
继承层次 继承并不限于一个层次 java中允许一个超类有多个子类,子类还可以扩展出子类。但是java中不允许有一个子类继承于多个超类,即java不支持多重继承,但是java提供了一种称为接口的东西实现多重继承的一些特性。 -
多态 java程序设计语言中,对象变量是多态的,一个x类型的变量既可以引用一个x类型的对象,也可以引用x类的任何一个子类的对象。子类的对象也是超类的对象,超类对象的任何地方都可以使用子类对象替换,但不是子类的地方是不能用超类随便替换的。见下图的staff[0]与boss。下图中Manager类是继承于Employee类的子类,变量**staff[0]**引用了Manager类的对象。
var boss = new Manager("Carl Cracker", 80000, 1987, 12, 15);
boss.setBonus(5000);
var staff = new Employee[3];
staff[0] = boss;
虽然**staff[0]**可以引用Manager类的对象,但是却不能直接调用Manager的方法。
boss.setBonus(5000);\\正确
staff[0].setBonus(5000);\\错误
多态:相同的消息给予不同的对象会引发不同的动作。 多态可分为变量多态与函数多态 变量多态:基类型的变量可以被赋值为基类型对象,也可以被赋值其子类的对象。 函数多态:相同的函数调用,传送给一个对象变量,可以有不用的行为,视该对象变量的对象类型而定。 成员变量覆盖无法实现像方法覆盖那样的多态性。 对象能够执行哪些方法是由引用的类型所决定的,而对象具体怎样去执行某个方法,却是由对象自己决定的。 在对象进行向下转型时,必须首先发生对象向上转型,否则将出现对象转换异常。 6. 理解方法调用 方法调用的执行有两个过程,第一: 找候选寻找该类以及该类的超类中(只有超类的公共方法才能被调用)名字为该方法名的方法。第二:匹配:重载解析 第三:特殊方法的静态绑定调用 private、static方法、final方法采用静态绑定的方式调用。 第四:一般方法的动态绑定调用,java虚拟机将生成方法表进行查找 静态绑定(前期绑定):在程序运行前就知道方法是属于那个类的,在编译的时候就可以链接到类中,定位到这个方法 动态绑定(后期绑定):程序运行过程中,根据具体实例对象才能具体确定是那个方法。
-
阻止继承:final类和方法 不允许扩展的类称为final类(注意:此处是用来修饰类的),前面我们只见过final修饰字段或者方法,如果类中的方法使用final修饰符,子类就不能覆盖这个方法。 如果一个类被声明为final类,那么它的方法会自动成为final方法,但是字段的性质不发生改变。 一旦阻止继承,就不能使用多态的有关性质了。 -
强制类型转换 普通的基本类型的强制类型转换,类的强制类型转换:将某个类的对象引用转化为另一个类的对象引用
Manager boss=(Mannger)staff[0];
Manager boss=(Manager)staff[1];
if(staff[i] instanceof Manager)
{
boss=(Manager) staff[1];
}
String c=(String) staff[1];
将一个子类的引用赋值给一个超类,可以,但是不可以把一个超类的引用强制类型转换给一个子类。 类的强制类型转换原则: 只能在继承原则中进行强制类型转换 在将超类转换为子类之前,应该使用 instanceof进行检查。
- 抽象类
关键字:abstract 高层次抽象类的必要性 抽象方法(有抽象方法的类必须定义为抽象的) 抽象类不能实例化,不能创建对象,但可以有类变量引用非抽象子类的对象
new Person("Vince Vu");
Person p=new Student("Vince Vu","Economics");
抽象方法将会用在“接口”中
-
受保护访问 关键字:protected java中,保护字段只能有一个包中的类访问。限制某个方法的使用可以使用protected字段。 -
Object:所有类的超类 java中的每个类都是Object继承来的。 Object对象可以引用任何类型的对象。在java中,数组类型都扩展了Object类。 equals方法 特性: 自反性 对称性 传递性 一致性 hashCode方法 散列码是由对象导出的一个整型值,散列码没有规律。 相等的对象要求给返回相等的散列码。 因为Object中定义了hashCode()方法,所以任何对象都具有hashCode方法。Object中的hashCode方法是通过对象的存储地址导出散列码。 String类重新定义了hashCode方法,使得其根据字符串的内容导出散列码 重新定义了equals方法就必须重新定义hashCode方法。
toString方法 返回对象值的一个字符串。 对象与一个字符串通过操作符“+”连接起来,java编译器就会自动的调用toString方法来获得这个对象的字符串描述 一般来说,我们直接输出一个对象,会输出对象的类名以及散列码,因为我们的类中并没有覆盖toString方法。 举个例子:数组类型继承了Object类的toString方法,且没有对其进行覆盖,如果我们要输出正常的数组值,是调用静态方法Arrays.toString。 作用:toString方法使得用户能够获取对象状态的有用信息。
- 泛型数组列表
java允许在运行时确定数组的大小
int actualSize=...;
var staff=new Employee[actualSize];
java中的ArrayList类(一个有类型参数的泛型类),类似于数组,但在添加或者删除元素时,能够自动的调整数组的容量,而不需要为此编写任何代码。 数组列表的声明
var staff=new ArrayList<Employee>();\\正确
ArrayList<Employee> staff=new ArrayList<>();\\正确
var staff=new ArrayList<>();\\错误,会生成Arraylist<Object>类
staff.size()\\获取列表的真实大小
staff.ensureCapacity(100);\\预先分配数组的大小
staff.trimTosize()\\削减数组的多余空间,回收多余的空间
ArrayList类不能用[]语法格式访问或改变数组的元素,而是要用get和set方法
staff.set(i,harry)
Employee e=staff.get(i);
int n=staff.size()/2;
staff.add(n,e)
staff.remove(n)
ArrayList插入与删除元素的操作效率很低,如果多次的在中间插入、删除,就应该考虑使用链表 由于java在发展的过程中,不加类型参数的原始数组列表的存在,我们需要与原始数组列表进行交互,在进行相互赋值的时候会出现警告错误。
- 对象包装器与自动装箱
所有的基本数据类型都有一个与之对应的类,这些类称为包装器,包装类是不可变的,且包装类都为final修饰,不可派生其子类。 具有类型参数的泛型类类型参数部分不能使用基本类型 自动装箱与自动拆箱使得一些简单的操作得以方便的实现。 装箱与拆箱是编译器要做的工作,而不是虚拟机。 如果在一个表达式中,混合使用Integer与Double,那么Integer会自动拆箱提升为double
int x=Integer.parseInt(s);
-
反射 反射库可以用来编写能够动态操纵java代码的程序。 能够分析类能力的程序称为反射 -
参数数量可变的方法 这些方法称为变参方法(System类的构造方法是private的,所以无法创建该类的对象,也就是无法实例化该类。他的属性和方法都是static的,所以也可以很方便的进行调用。调用方式 就是 类型.属性名称/方法名)
https://www.yunlibook.com/article/1412722316089098240
public class PrintStream
{
public PrintStream printf(String fmt, Object ... args){ return format(fmt,args);}
}
其中省略号…表明这个方法可以接受任意数量的对象。
System.out.println("%d %s",n,"widgets");
System.out.printf("%d %s",new Object[]{new Integer(n),"widgets"});
自己定义参数可变的方法,类型可以是基本类型
- 枚举类
枚举类不可能构造新的对象,其构造函数被设计为private的
enum Color {
RED, GREEN, BLUE
}
public enum Size
{
SMALL("S"),MEDIUM("M"),LARGE("L"),EXTRA_LARGE("XL");
private String abbreviation;
private Size(String abbreviation){this.abbreviation=abbreviation;}
public String getAbbreviation()
{
return abbreviation;
}
}
- 设计技巧
将公共操作和字段放在超类中 不要使用受保护的字段 使用多态,而不要用类型信息
|