目录
封装性
封装性的设计思想
Java规定的四种权限修饰符
继承性
继承性的好处
类继承语法规则
子类继承父类以后的特点
多态性(重要)
引用变量的两个类型
编译时类型
运行时类型
多态的应用举例
多态性的使用:虚拟方法调用(Virtual Method Invocation)
正常方法的调用
虚拟方法调用(多态情况下)
多态小结
instanceof操作符
对象类型转换(Casting)
封装:
程序设计追求“高内聚,低耦合”。
高内聚:类的内部数据操作细节自己完成,不允许外部干涉;
低耦合:仅对外暴露少量的方法用于使用;
隐藏:
隐藏对象内部的复杂性,只对外公开简单的接口。便于外界调用,从而提高系统的可扩展性、可维护性。通俗的说,把该隐藏的隐藏起来,该暴露的暴露出来。
//封装性思想具体的代码体现
//体现一:针对属性
private double radius; //将类的属性私有化(private)
public void setRadius(double radius){
this.radius = radius;
}
public double getRadius(){ //同时提供公共的(public)方法来获取和设置此属性的值。
return radius;
}
//体现二:针对方法
private int getRandomNum(){ //私有化方法,不对外暴露
return (int)(Math.random()*100);
}
//体现三:针对构造器(单例模式)
class Bank{
private Bank(){ //私有化类的构造器
}
private static Bank instance = new Bank();
public static Bank getInstance(){
return instance;
}
}
//体现四:如果不希望类在包外被调用,可以将类设置为缺省的。
权限从小到大顺序为:private < 缺省 < protected < public
以上四种权限修饰符都可以用来修饰类的内部结构:属性、方法、构造器、内部类
但修饰类的话,只能使用:缺省、public
① 减少了代码的冗余,提高了代码的复用性。
② 便于功能的扩展。
③ 为之后多态性的使用,提供了前提。
注意:不要 仅为了获取其他类中某个功能而去继承
class Subclass extends SuperClass{ }
/**
* Student类继承了父类Person的所有属性和方法,并增加了一个属性school。
* Person中的属性和方法,Student都可以使用。
*/
class Person {
public String name;
public int age;
public Date birthDate;
public String getInfo(){
//......
}
}
class Student extends Person {
public String school;
}
子类Student继承父类Person后,子类Student中就获取了父类Person中声明的所有属性和方法。注意:即使父类中声明为private的属性或方法,子类继承以后,仍然认为获取了父类中的私有的结构,只是由于封装性的影响,使得子类不能直接调用父类中的私有结构而已。
子类继承父类以后,还可以声明自己特有的属性或方法,实现了功能的拓展。子类和父类的关系不同于子集和集合的关系。
说明
1、一个类可以被多子类继承。
2、Java中类的单继承性:一个类只能有一个父类。可以多层继承但不能多重继承。
3、子父类是相对的概念。
4、子类直接继承的父类称为直接父类;子类间接继承的父类称为间接父类。
5、子类继承父类以后,就获取了直接父类以及所有间接父类中声明的属性和方法。
6、如果没有显示的声明一个类的父类,则此继承于java.lang.Object类。
7、所有的java类(除java.lang.Object类)都直接或间接继承于java.lang.Object类。
8、所有的java类都具有java.lang.Object类声明的功能。
//几何图形
public abstract class GeometricObject {
protected String color;
protected double weight;
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public double getWeight() {
return weight;
}
public void setWeight(double weight) {
this.weight = weight;
}
public GeometricObject(String color, double weight) {
super();
this.color = color;
this.weight = weight;
}
public abstract double findArea();
}
//圆,继承于几何图形
public class Circle extends GeometricObject {
private double radius;
public Circle(double radius,String color, double weight) {
super(color, weight);
this.radius = radius;
}
public double getRadius() {
return radius;
}
public void setRadius(double radius) {
this.radius = radius;
}
public double findArea(){
return 3.14 * radius * radius;
}
}
可以理解为一个事物的多种形态。
对象的多态性指:父类的引用指向子类的对象或者说子类的对象赋给父类的引用。(向上转型)
Person p = new Student(); //Person类型的变量p,指向Student类型的对象
Object o = new Person(); //Object类型的变量o,指向Person类型的对象
o = new Student(); //Object类型的变量o,指向Student类型的对象
由声明该变量时使用的类型决定
由实际赋给该变量的对象决定
总结:编译时看左边;父类引用(父类中不具备子类特有的方法)
运行时看右边。子类对象(实际运行的是子类重写父类的方法)
若编译时类型和运行时类型不一致,就出现了对象的多态性。
一个变量只能有一种确定的数据类型。
一个引用变量可能指向多种不同类型的对象。
public class Test {
public void method(Person p){ //方法的参数类型为父类Person类型
p.getInfo();
//...
}
public static void main(String args[]){
Test test = new Test();
Student s = new Student();
test.method(s); // 子类的对象s传给父类类型的参数p
}
}
Person p = new Person();
p.getInfo();
Student s = new Student();
s.getInfo();
子类中定义了与父类同名同参数的方法,在多态情况下,将此时父类的方法称为虚拟方法,父类根据赋给它的不同子类对象,动态调用属于子类的该方法。这样的方法调用在编译期是无法确定的。
Person p = new Student();
p.getInfo(); //调用的是Student类中的getInfo()方法
解释: 编译时p为Person类型,而方法的调用是在运行时确定的,所以调用的是Student类的getInfo()方法。称为 动态绑定
重载:
是指允许存在多个同名方法,而这些方法的参数不同。 编译器根据方法不同的参表,对同名方法的名称做修饰。对于编译器而言,这些同名方法就成了不同的方法。它们的调用地址在编译期就绑定了。Java的重载是可以包括父类和子类的,即子类可以重载父类的同名不同参数的方法。所以:对于重载而言,在方法调用之前,编译器就已经确定了所要调用的方法,这称为“ 早绑定” 或 “ 静态绑定 ”。
多态:
只有等到方法调用的那一刻解释运行器才会确定所要调用的具体方法,这称为 “晚绑定”或“动态绑定 ” 。
Bruce Eckel 说过:“不要犯傻,如果它不是晚绑定它就不是多态。”
多态作用
提高了代码的通用性,常作接口重用。
前提
存在继承或实现关系,有方法的重写。
成员方法
编译时:要查看引用变量所声明的类中是否有所调用的方法。
运行时:调用实际new 的对象所属的类中的重写方法 。
成员变量(属性)
不具备多态性(即编译和运行都看左边)
a instanceof A:检验x是否为类A的对象,返回值为boolean型。
要求x所属的类与类A必须是子类与父类的关系,否则编译报错。
public class Person extends Object{
//...
}
public class Student extends Person{
//...
}
public class Graduate extends Person{
//...
}
public void method(Person p){
if (p instanceof Person)
//处理 Person 类及其子类对象
if (p instanceof Student)
//处理 Student 类及其子类对象
if (p instanceof Graduate)
//处理 Graduate 类及其子类对象
}
基本数据类型的Casting:
自动类型转换:小的数据类型可以自动转换成大的数据类型。
如: long b = 2; double d = 12.0f
强制类型转换: 如: float f = (float)12.3; int a = (int)120L
对象的强制类型转换:
从子类到父类的类型转换可以自动进行。
从父类到子类的类型转换必须强制类型转换。
无继承关系的引用类型间的转换是非法的。
强制类型转换前可以使用instanceof操作符测试一个对象的类型
举例:
double d = 12.3;
long l = (long) d; //基本数据类型的强制转换
Object obj = "Hello";
String objStr = (String) obj; //对象类型的强制转换
Object objInt = new Integer(2);
String str = (String) objInt; //会引起ClassCastException异常
public void method(Person p){ //设Person类中没有getSchool()方法
//如果直接p.getSchool(),会编译错误
if(p instanceof Student){
Student stu = (Student) p; //将p 强制转换为Student类型
System.out.println(stu.getSchool());
}
}