对象的封装和继承详解
面向对象三大特性
1.封装
-
引言
- 在我们的项目中只有一个实现类main,在main中将类实例化为对象,通过对象来调用类中的方法,属性,有参与无参构造函数,对私有属性private的访问get/set方法
- 在类中具有方法,属性,有参与无参构造函数,对私有属性private的访问get/set方法
-
该露的露,该藏得藏
- 我们程序设计要追求 “高内聚,低耦合”。高内聚就是将类的内部数据操作细节自己完成,不允许外部干涉;
- 低耦合:尽量暴露少量的方法给外部使用。
-
封装(数据的隐藏)
- 通常,应禁止直接访问一个对象中数据的实际表示,而应通过操作接口来访问,这称为信息隐藏。
-
通过private 达到属性私有;通过 get / set来访问数据 ;
- 有时候我们可在set方法中做一些数据安全性的判断。
-
封装的好处:
- 1.提高程序的安全性,保护数据
- 2.隐藏代码的实现细节
- 3.统一接口
- 4.系统可维护性增加了
1.1 封装代码演示:
package oopdemo01;
import oopdemo01.demo03.Pet;
import oopdemo01.demo04.Student;
public class Application {
public static void main(String[] args) {
Student s1 = new Student();
System.out.println(s1.getName());//null
s1.setName("小明");//通过get/set方法来给实例化后的对象的某些私有属性赋初值
s1.setAge(100);//不合法
System.out.println(s1.getName());//输出快捷键:s1.getName().sout+回车
System.out.println(s1.getAge());
}
}
package oopdemo01.demo04;
public class Student {
//类 private:属性私有
private String name;// 名字
private int age; // 年龄
private int id; // 学号
private char sex; // 性别
public void study(){
}
//提供一些可以操作这个属性的方法
//public的get,set方法
// set/get 快捷键 Alt+insert 选get and set 按住Ctrl加鼠标是多选
//get 获得这个数据
public String getName(String name){
return name;
}
// set 给这个数据设置值
public void setName(String name){
this.name=name;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
//可以在set方法中编写代码来对输入的数据进行合法性的判断
public void setAge(int age) {
if(age>=120||age<0){
System.out.println("年龄不合法");
}else {
this.age = age;
}
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public char getSex() {
return sex;
}
public void setSex(char sex) {
this.sex = sex;
}
}
运行结果
null
小明
100
2.继承详解
-
引言
- 属性加方法构成了一个类,类如果太多了,那么也得进行抽象。比如人还可以分为中国人,美国人,英国人...继承的本质是对某一批类的抽象,从而实现对现实世界更好的建模。
- 封装是底层的东西,是具体的代码实现。继承是最核心的东西,是一个宏观的把握
-
继承关系的两个类,一个为子类(派生类),一个为父类(基类)。子类继承父类,使用关键字extends来表示。
-
extends 的意思是“扩展”。子类是父类的扩展。
-
Java 中类只有单继承,没有多继承!即爸爸可以有多个儿子,但儿子只能有一个爸爸。
-
继承是类与类之间的一种关系。除此之外,类与类之间的关系还有依赖、组合、聚合等。
-
子类和父类之间,从意义上将应该具有”is a“的关系。
-
子类继承了父类,就会拥有父类的全部方法(public)
-
继承是类与类之间的关系。子类可以继承父类的所有public方法和属性,private私有关键字修饰的方法和属性是无法被继承的,但也可以通过get和set方法来获取私有的属性
-
-
object类: 在 Java 中,所有的类,都默认、直接或者间接继承object
- 查看继承关系的快捷键: ctrl+H
-
修饰符:
- 1.public 公共的
- 2.protected 受保护的
- 3.default 默认的
- 4.private 私有的
2.1 继承代码演示:
package oopdemo01.demo05;
//人 :父类
public class Person {
//父类中有私有的money属性和公共的say方法
private int money=1_0000_0000;
public void say(){
System.out.println("开口说话了");
}
public int getMoney() {
return money;
}
public void setMoney(int money) {
this.money = money;
}
}
package oopdemo01.demo05;
//学生 is 人: 派生类,子类
//子类继承了父类,就会拥有父类的全部方法
public class Student extends Person{
//子类student 继承了父类person 中的所有未被私有的属性和方法,但子类中并没有定义自己的方法和属性
}
package oopdemo01;
import oopdemo01.demo03.Pet;
import oopdemo01.demo05.Student;
//测试类
public class Application {
public static void main(String[] args) {
//在测试类中new出子类对象,然后通过子类对象名来调用所有继承的父类中的方法
Student s1 = new Student();
s1.say();
System.out.println(s1.getMoney()); //由于父类的属性被private修饰,所有必须通过get /set 方法获取
//继承是类与类之间的关系。子类可以继承父类的所有public方法和属性,private私有关键字修饰的方法和属性是无法被继承的,但也可以通过get和set方法来获取私有的属性
}
}
运行结果
开口说话了
100000000
————————————————————————————————————————————————————————————
3.super与this关键字
-
引言
- 私有的方法无法被继承,私有的属性也无法直接访问,但可以通过get和set方法来进行获取或者修改。
- super代表父类,this代表当前类
- 通过this和super调用可以简化大量的代码。
-
super与this对比
-
super注意点:
-
1. super调用父类的构造方法,必须在构造方法的第一个
-
2. super 必须只能出现在子类的方法或者构造方法中
-
3. super和this不能同时调用构造方法!
-
-
super VS this:
- 1.代表的对象不同:
- this:本身调用者这个对象
- super:代表父类对象的应用
- 2. 使用前提不同:
- this:没有继承也可以使用
- super:代表父类对象的引用
- 3. 构造方法:
- this():本类的构造
- super():父类的的构造
-
特别注意: 父类没有无参构造,子类不仅无法调用父类的无参构造也无法写自己的无参构造。所以一般我们写了有参构造,就自己手写无参构造,把无参构造函数加上。避免出错
3.1 属性和方法继承中this和supe作用代码演示:
package oopdemo01.demo06;
//Person 人:父类
public class Person {
protected String name="老子";
public Person() {
System.out.println("老子的无参构造执行了");
}
// 如果将print 方法的修饰符public 改为protected,
// super.test1 将调用失败,私有的东西无法被继承
public void print(){
System.out.println("老子的方法");
}
}
package oopdemo01.demo06;
// 学生 is 人
//子类继承了父类,就会拥有父类的全部方法
public class Student extends Person {
protected String name="小子";
public Student() {
// super(); 隐藏代码;调用了父类的无参构造
// 注意:调用父类的构造器,必须要在子类构造器的第一行。且this和super 不能同时存在
System.out.println("小子的无参构造执行了");
}
public void print(){
System.out.println("小子的方法");
}
public void test(String name){
System.out.println(name);//星辰
System.out.println(this.name);//小子
System.out.println(super.name);//老子
}
public void test1(){
print();//小子的方法
this.print();//小子的方法
super.print();//老子的方法
}
}
package oopdemo01.demo06;
public class Application {
public static void main(String[] args) {
Student student=new Student();//测试父类与子类的无参构造方法执行的先后顺序
//结论:构造函数在new对象时会被直接调用,测试类中new对象时,如果对象是继承类,先隐藏调用父类无参构造然后再调用子类的无参构造
student.test("星辰");//测试继承属性 this和 super
student.test1(); // 测试继承方法
}
}
运行结果
老子的无参构造执行了
小子的无参构造执行了
星辰
小子
老子
小子的方法
小子的方法
老子的方法
4.方法的重写
-
引言
- 当父类的功能,子类不一定需要,或者不一定满足。那么子类重写方法后就会替换掉父类继承给它的方法
- 快捷键:Alt+Insert 选 Override
- 重写与属性毫无关联,是方法的重写
- 方法的重写用在类与类的继承之间的,区别于方法的重载,方法重载是方法名相同,参数或者参数列表不同,而方法的重写是对具有继承关系的方法体内部的代码重新编写实现与父类不同的功能。
-
重写的条件:
-
需要有继承关系,子类重写父类的方法
-
1. 方法名必许相同
-
2.参数列表必须相同
-
3. 修饰符:范围可以扩大但是不能缩小 (Public->Protect->Default->Private)
-
4. 抛出的异常:范围可以被缩小,但不能扩大;ClassNotFoundException(小) —> Exception(大)
-
-
重写,子类的方法和父类必须一致,方法体不同!
-
注意:静态的方法和非静态的方法区别很大
- 重写的只能是子父类之间共有的public的方法:其一为public,其二为方法。
- 具有继承关系的两个类中的非静态方法才可以重写,new出的子类对象调用的都是子类中重写后的方法,而静态方法,也就是用static修饰的方法其实不是重写,只是定义了两个名字一样的方法而已。在测试类中new出子类方法,调用哪一个类的方法则要看接收这个对象的变量名的类是父类还是子类,是谁的类就调用谁的方法。
4.1 继承类中方法的重写代码演示:
package oopdemo01.demo06;
//父类
//重写都是方法的重写,和属性无关
public class A {
public static void test(){
System.out.println("A的方法=>test()");
}
public void test1(){
System.out.println("A的方法test1");
}
}
package oopdemo01.demo06;
//B继承A 子类
public class B extends A{
public static void test(){
System.out.println("B的方法=>test()");
}
/*
public void test1(){
System.out.println("B的方法test1");
}
*/
// Override 重写
@Override //注解:有功能的注释
public void test1() {
System.out.println("B的方法test1");
}
}
package oopdemo01.demo06;
public class ApplicationAB {
public static void main(String[] args) {
//静态的方法和非静态的方法区别很大
// 方法的调用只和左边定义的数据类型有关
B b = new B();
b.test();
//父类的引用指向子类
A a = new B();
a.test();
System.out.println("=====================");
// 非静态:重写
a.test1();
b.test1();
}
}
运行结果
B的方法=>test()
A的方法=>test()
=====================
B的方法test1
B的方法test1