面向对象的三个特征
封装机制在程序中的体现是:把描述对象的状态用字段表示,描述对象的行为用方法表示, 把字段和方法定义在一个类中,并保证外界不能任意更改其内部的字段值,也不允许任意调动其内部的功能方法。
封装:通常将类中的成员变量私有化(private),通过对外提供方法(setXxx,getXxx),可对该变量(xxx)进行访问。 boolean 类型的变量没有getXX,只有 isXX;
public class Person{ private String name; private int age; private int sal;
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }}
特点:
总结:继承是多态的前提。 对类而言,只支持单继承。接口可以实现多继承
格式:[修饰符]classSubClassextendsSuperClass
按照这种关系,我们把SuperClass类称为父类或基类,把SubClass称为子类或派生类或拓展类;
java.lang.Object
是所有类的父类,Object要么是直接父类要么是间接父类。 定义个类,如果没有显示指定 extends
继承某个类,那么默认继承 extendsObject
学生属于人的一种特殊情况,此时我把人的共性写在Person类里面,为了让学生拥有这些共性,然后我就让学生来拓展Person类。
public class Student extends Person {
private String number;
public String getNumber() { return number; }
public void setNumber(String number) { this.number = number; }
public void study() { System.out.println("study"); }}
public class StudentDemo { public static void main(String[] args) { Person p = new Person(); p.setName("TOM"); p.setAge(20); System.out.println("我是:" + p.getName() + ",今年" + p.getAge() + "岁。");
Student s = new Student(); //Student中并没有显示的定义setName和setAge这两个方法,为什么可以使用呢? //因为Student继承自Person,所以可以使用父类中的非私有属性和非私有方法 //在开发中,我们在优化代码的过程中,经常会将某几类共有的属性和方法向上提取,构造一个父类 s.setName("Lucy"); s.setAge(18); s.setNumber("20180978"); System.out.println("我是:" + s.getName() + ",今年" + s.getAge() + "岁,我的学号是:" + s.getNumber()); }
}
总结:子类与父类的关系:
注意:
概述:
用途:
调用构造方法
this(参数列表)
super(参数列表)
注意 子类调用父类的构造方法时: super必须放在第一句
初始化子类会优先初始化父类的数据.因为子类要继承父类的属性和方法,所以初始化子类时首先调用父类的构造方法。
修改person类:
public class Person { private String name; private int age; private int sal;
public Person(){ System.out.println("person 的无参构造"); }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }}
修改后的Student类:
public class Student extends Person {
private String number;
public Student() { System.out.println("Student无参构造方法"); }
public Student(String number) { System.out.println("Student的有参构造"); this.number = number; }
public String getNumber() { return number; }
public void setNumber(String number) { this.number = number; }
public void study() { System.out.println("study"); }}
测试类:
public class StudentDemo { public static void main(String[] args) { // 使用无参构造创建Student的对象 new Student(); // 使用有参构造创建Student的对象 new Student("100101");
/* 打印结果: person 的无参构造 Student无参构造方法 person 的无参构造 Student的有参构造
*/
}
}
思考:如果父类没有无参构造这么办?
修改Person的构造方法,注意是修改,不是添加。只要类中有带参数的构造,无参构造方法将不会默认添加
public Person(String name){ System.out.println("person 的无参构造"); this.name = name; }
修改如上代码之后,点击保存。我们就会发现Student类中的两个构造方法报错。
修改Student的构造方法:
public Student() { super("TOM"); System.out.println("Student无参构造方法"); }
public Student(String number) { super("TOM"); System.out.println("Student的有参构造"); this.number = number; }
为什么父类没有无参构造,代码编译不通过?
因为子类构造默认调用父类的无参构造方法,super(),可以省略:
public Student() { super(); System.out.println("Student无参构造方法"); }
public Student(String number) { super(); System.out.println("Student的有参构造"); this.number = number; }
例如:
Person类中有私有字段name,Student继承Personnew Sudent().name; ×new Student().getName(); √
产生原因
当父类中某个方法不适合于子类时,子类出现父类一模一样的方法.
特点:
@Override public void setAge(int age) { System.out.println("Student类对setAge()方法自定义"); super.setAge(age); }
如上所示: 我们可以在Student类中重写父类的setAge方法,并在内部实现自己的逻辑。 建议使用@Override注解进行标注重写的方法,因为如果不是重写的方法该注解会在编译器报错
子类重写了方法,使用子类对象调用时,最终执行的就是子类重写的方法。 new Student().setAge(11); 执行结果:会打印【Student类对setAge()方法自定义】这句话
概述:
多态,通俗说就是一个物体多种状态,比如水有气态,固态,液态。
表现形式:
例如:
前提: Student extends Person
在StudentDemo测试类中添加下列代码:
Person ps = new Student();//这就是多态
在编译时期 ps 对象是Person,但是在运行时期 ps 对象 是Student
比如我们上面在Student类中重写了Person类中的setAge方法,那么你使用 ps 这个对象来调用setAge(111) 方法,他运行的就是Student类中重写的方法
实现多态的机制:
父类的引用变量可以指向子类的实例对象,而程序调用的方法在运行期才动态绑定, 就是引用变量所指向的真正实例对象的方法,也就是内存里正在运行的那个对象的方法, 而不是引用变量的类型中定义的方法。
多态的作用
把不同的子类对象都当作父类来看,可以屏蔽不同子类对象之间的差异,写出通用的代码,做出通用的编程,以适应需求的不断变化。 只修改方法的实现,不必修改方法的声明。java中有面向接口编程也极大的展示了多态的特性。
继承/接口实现 是多态产生的前提条件
向上转型(子类 →父类):由子类转为父类
父类名称 父类对象 = 子类实例 ; Person ps = new Student();
向下转型(父类 → 子类):由父类转为子类 使用强制类型转换 子类名称 子类对象 = (子类名称)父类实例 ; Person ps = new Student(); ps.setAge(123); Student ss = (Student) ps;
向下转型注意:
创建一个Worker类同时继承Person:
public class Worker extends Person{ private String job;
public void setJob(String job) { this.job = job; }
public String getJob() {
return job; }}
在StudentDemo的main方法中,添加: Person pw = new Worker(); Student sss = (Student) pw;
将一个Worker强转为Student。 会报异常:java.lang.ClassCastException:Worker cannot be cast to Student
如何判断pw是否是Student类型呢?使用instanceof关键字 Person pw = new Worker();
if (pw instanceof Student) { Student sss = (Student) pw; }
对象名 instanceof 类
判断指定的变量名此时引用的真正类型是不是当前给出的类或子类;