Java基础——面向对象(二)(封装、继承、多态)


一、封装(Encapsulation)

封装是把过程和数据包围起来,对数据的访问只能通过已定义的接口。面向对象计算始于这个基本概念,即现实世界可以被描绘成一系列完全自治、封装的对象,这些对象通过一个受保护的接口访问其他对象。封装是一种信息隐藏技术,在java中通过关键字private, protected和public实现封装。什么是封装?封装把对象的所有组成部分组合在一起,封装定义程序如何引用对象的数据,封装实际上使用方法将类的数据隐藏起来,控制用户对类的修改和访问数据的程度。适当的封装可以让程式码更容易理解和维护,也加强了程式码的安全性。

程序设计追求“高内聚,低耦合”:

  1. 高内聚:类的内部数据操作细节自己完成,不允许外部干涉;
  2. 低耦合:仅对外暴露少量的方法用于使用。

隐藏对象内部的复杂性,只对外公开简单的接口。便于外界调用,从而提高系统的可扩展性、可维护性,提高代码的安全性。通俗的说,把该隐藏的隐藏起来,该暴露的暴露出来。这就是封装性的设计思想。

public class Girl {//女孩
    //属性:
    private int age;
    //读取年龄:
    public int duquAge(){
        return age;
    }
    //设置年龄:
    public void shezhiAge(int age){
        if(age >= 30 ){
            this.age = 18;
        }else{
            this.age = age;
        }
    }
}
public class Test {
    //这是一个main方法,是程序的入口:
    public static void main(String[] args) {
        //创建一个Girl类的对象:
        Girl g = new Girl();
        /*g.age = 33;
        System.out.println(g.age);*/
        //设置年龄:
        g.shezhiAge(31);
        //读取年龄:
        System.out.println(g.duquAge());
    }
}

上面的代码,对于属性age来说,我加了修饰符private,这样外界对它的访问就受到了限制,现在我还想加上其他的限制条件,但是在属性本身上没有办法再加了,所以我们通过定义方法来进行限制条件的添加。
以属性为案例:进行封装:

  1. 将属性私有化,被private修饰 —> 加入权限修饰符,一旦加入了权限修饰符,其他人就不可以随意的获取这个属性
  2. 提供public修饰的方法让别人来访问/使用
  3. 即使外界可以通过方法来访问属性了,但是也不能随意访问,因为咱们在方法中可以加入限制条件。

实际开发中,方法一般会写成 setter,getter方法:
可以利用IDEA快捷键生成:alt+insert —> getter and setter:

public class Girl {//女孩
    //属性:
    private int age;
    //读取年龄:
    public int getAge(){
        return age;
    }
    //设置年龄:
    public void setAge(int age){
        if(age >= 30 ){
            this.age = 18;
        }else{
            this.age = age;
        }
    }
}
public class Student {
    //属性:
    private int age;
    private String name;
    private String sex;
    //加入对应的setter和getter方法:
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getSex() {
        return sex;
    }
    public void setSex(String sex) {
        if("男".equals(sex) || "女".equals(sex) ){//sex是男 或者 是 女
            this.sex = sex;
        }else{
            this.sex = "男";
        }
    }
    //加入构造器:
    public Student(){
    }
    public Student(int age,String name,String sex){
        this.age = age;
        this.name = name;
        //this.sex = sex;
        this.setSex(sex);
    }
}
public class Test {
    //这是一个main方法,是程序的入口:
    public static void main(String[] args) {
        //创建一个Student对象:
        Student s1 = new Student();
        s1.setName("nana");
        s1.setAge(19);
        s1.setSex("女");
        System.out.println(s1.getName()+"---"+s1.getAge()+"----"+s1.getSex());
        Student s2 = new Student(18,"菲菲","asdfasdfsadf");
        System.out.println(s2.getName()+"---"+s2.getAge()+"----"+s2.getSex());
    }
}

二、继承(Inheritance)

1. 继承

是对对象的抽象;继承是对的抽象。
继承关系,是在合理的范围中进行的抽取 ,抽取出子类父类的关系(继承 就是 is - a 的关系) :

  • 员工是一个人 —> 合理
  • 学生是一个狗 —> 不合理
public class Person {
    //属性:
    private int age;
    private String name;
    private double height;
    //提供setter getter方法:
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public double getHeight() {
        return height;
    }
    public void setHeight(double height) {
        this.height = height;
    }
    //方法:
    public void eat(){
        System.out.println("可以吃饭。。。");
    }
    public void sleep(){
        System.out.println("可以睡觉。。。");
    }
}
public class Student extends Person {//子类Student 继承  父类Person
    //属性:
    private int sno;//学号
    public int getSno() {
        return sno;
    }
    public void setSno(int sno) {
        this.sno = sno;
    }
    //方法:
    public void study(){
        System.out.println("学生可以学习");
    }
}
public class Test {
    //这是一个main方法,是程序的入口:
    public static void main(String[] args) {
        //创建子类Student的对象
        Student s = new Student();
        s.setSno(1001);
        s.setAge(18);
        s.setName("菲菲");
        s.setHeight(180.4);
        System.out.println("学生名字为:"+s.getName()+",学生的年纪:"+s.getAge());
        //访问方法:
        s.study();
        s.eat();
        s.sleep();
    }
}

总结:

  1. 继承提高了代码的复用性,父类定义的内容,子类可以直接拿过来用就可以了,不用代码上重复定义了。便于代码的扩展。
  2. 为了以后多态的使用。是多态的前提。
  3. 父类private修饰的内容,子类实际上也继承,只是因为封装的特性阻碍了直接调用,但是提供了间接调用的方式,可以间接调用
  4. 一个父类可以有多个子类,一个子类只能有一个直接父类
  5. 继承具有传递性:Student —> 继承自 Person —> 继承自Object
    Object类是所有类的根基父类。所有的类都直接或者间接的继承自Object。

继承的内存分析:
在这里插入图片描述

2. 权限修饰符

同一个类同一个包子类所有类
private*
default**
protected***
publlic****

一般属性:用private修饰
方法:用public修饰

3. 方法的重写

重写:发生在子类和父类中,当子类对父类提供的方法不满意的时候,要对父类的方法进行重写。
子类的方法名字和父类必须一致,参数列表(个数,类型,顺序)也要和父类一致。

public class Person {
    public void eat(){
        System.out.println("吃食物");
    }
    public void sleep(){
        System.out.println("睡觉");
    }
}
public class Student extends Person {
    public void study(){
        System.out.println("学习");
    }
                                        @override
    public void eat(){
        System.out.println("我喜欢吃小龙虾喝啤酒。。");
    }
}
public class Test {
    //这是一个main方法,是程序的入口:
    public static void main(String[] args) {
        //创建一个Student类的对象:
        Student s = new Student();
        s.eat();
    }
}

在这里插入图片描述
内存分析:
在这里插入图片描述
重载和重写的区别:

  1. 重载:在同一个类中,当方法名相同,形参列表不同的时候 多个方法构成了重载
  2. 重写:在不同的类中,子类对父类提供的方法不满意的时候,要对父类的方法进行重写。
英文位置修饰符返回值方法名参数抛出异常方法体
重载overload同一个类中无关无关必须相同必须不同无关不同
重写override子类父类中无关父类的权限修饰符要低于子类的父类的返回值类型大于子类必须相同必须相同小于等于

4. super

super指的父类的。super可以修饰属性,可以修饰方法。

  1. 在子类的方法中,可以通过 super.属性、super.方法 的方式,显示地去调用父类提供的属性、方法。在通常情况下,super. 可以省略不写 在这里插入图片描述
  2. 在特殊情况下,当子类和父类的属性或方法重名时,你要想使用父类的属性或方法,必须加上修饰符 super. ,只能通过 super. 方法来调用在这里插入图片描述

super修饰构造器:

  1. 其实我们平时写的构造器的第一行都有:super() —> 作用:调用父类的空构造器,只是我们一般都省略不写。在这里插入图片描述
  2. 如果构造器中已经显示的调用super父类构造器,那么它的第一行就没有默认分配的super();了在这里插入图片描述
  3. 在构造器中,super调用父类构造器和this调用子类构造器只能存在一个,两者不能共存:因为super修饰构造器要放在第一行,this修饰构造器也要放在第一行:在这里插入图片描述

继承条件下构造方法的执行过程: 一层一层super

在这里插入图片描述

5. object类

所有类都直接或间接的继承自Object类,Object类是所有Java类的根基类。
也就意味着所有的Java对象都拥有Object类的属性和方法。
如果在类的声明中未使用extends关键字指明其父类,则默认继承Object类。
在这里插入图片描述


5.1 toString()

在这里插入图片描述
但使用toString()方法的时候,打印出来的东西 “不好看”,对于其他人来说不友好,可读性不好。我们现在是想知道对象的信息,名字,年龄,身高。
现在的格式不好:在这里插入图片描述
出现的问题:子类Student对父类Object提供的toString()方法不满意,不满意 —> 对toString方法进行重写

public class Student /*extends Object*/{
    private String name;
    private int age;
    private double height;
    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;
    }
    public double getHeight() {
        return height;
    }
    public void setHeight(double height) {
        this.height = height;
    }
    public Student() {
    }
    public Student(String name, int age, double height) {
        this.name = name;
        this.age = age;
        this.height = height;
    }
    //重写toString()
    public String toString() {
        return "这是一个Student对象,这个对象的名字:"+name+",年龄:"+age+",身高:"+height;
    }
}

在这里插入图片描述
IDEA提供了重写toString()快捷键: Alt+Insert

/*public String toString() {
        return "这是一个Student对象,这个对象的名字:"+name+",年龄:"+age+",身高:"+height;
    }*/
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", height=" + height +
                '}';
    }
}

5.2 equals()

equals作用:这个方法提供了对对象的内容是否相等 的一个比较方式,对象的内容指的就是属性。
boolean flag = p1.equals(p2);
父类Object提供的equals就是在比较==地址,没有实际的意义,我们一般不会直接使用父类提供的方法,而是在子类中对这个方法进行重写。
在这里插入图片描述

  1. Eclipse在这里插入图片描述
  2. IDEA在这里插入图片描述

6.类的关系

在这里插入图片描述在这里插入图片描述类和类可以产生关系:
将一个类作为另一个类中的方法的形参;将一个类作为另一个类的属性。

public class Girl {
    //属性:
    String name;
    double weight;
    Mom m /*= new Mom()*/;
    //方法:
    public void add(int a){//参数是基本数据类型
        System.out.println(a);
        System.out.println(a+100);
    }
    //谈恋爱的方法:
    public void love(Boy b){//参数是引用数据类型Boy
        System.out.println("我男朋友的名字是:"+b.name+",我男朋友的年龄是:"+b.age);
        b.buy();
    }
    //女孩跟妈妈聊天:
    public void wechat(){
        m.say();
    }
    //构造器:
    public Girl(String name, double weight) {
        this.name = name;
        this.weight = weight;
    }
}
public class Boy {
    //属性:
    int age;
    String name;
    //方法:
    public void buy(){
        System.out.println("跟我谈恋爱,我给你买买买。。。");
    }
    //构造器:
    public Boy(int age, String name) {
        this.age = age;
        this.name = name;
    }
}
public class Mom {
    //方法:
    public void say(){
        System.out.println("妈妈唠唠叨叨 都是爱,听妈妈的话。。");
    }
}
public class Test {
    //这是一个main方法,是程序的入口:
    public static void main(String[] args) {
        //创建一个Boy类的具体的对象:
        Boy boy = new Boy(30,"鹿晗");
        //创建一个Girl类的具体的对象:
        Girl girl = new Girl("关晓彤",100);
        //谈恋爱:
        //girl.love(boy);
        Boy boy2 = new Boy(35,"陈伟霆");
        girl.love(boy2);
        //还可以跟妈妈微信聊天:
        girl.m = new Mom();
        girl.wechat();
    }
}

三、多态(polymorphism)

1. 多态

public class Animal {//父类:动物:
    public void shout(){
        System.out.println("我是小动物,我可以叫。。。");
    }
}

public class Cat extends Animal{
    //喊叫方法:
    public void shout(){
        System.out.println("我是小猫,可以喵喵叫");
    }
    public void scratch(){
        System.out.println("我是小猫,我可以挠人");
    }
}
public class Dog extends Animal{
    //喊叫:
    public void shout(){
        System.out.println("我是小狗,我可以汪汪叫");
    }
    public void guard(){
        System.out.println("我是小狗,我可以看家护院,保护我的小主人。。。");
    }
}
public class Pig extends Animal{
    public void shout(){
        System.out.println("我是小猪,我嗯嗯嗯的叫");
    }
    public void eat(){
        System.out.println("我是小猪,我爱吃东西。。");
    }
}
public class Girl {
    //跟猫玩耍:
    /*public void play(Cat cat){
        cat.shout();
    }*/
    //跟狗玩耍:
    /*public void play(Dog dog){
        dog.shout();
    }*/
    //跟小动物玩耍:
    public void play(Animal an){
        an.shout();
    }
}

public class Test {
    //这是一个main方法,是程序的入口:
    public static void main(String[] args) {
        //具体的猫:--》猫的对象
        //Cat c = new Cat();
        //具体的小女孩:--》女孩的对象
        Girl g = new Girl();
        //小女孩跟猫玩:
        //g.play(c);
        //具体的狗---》狗的对象:
        //Dog d = new Dog();
        //小女孩跟狗玩:
        //g.play(d);
        //具体的动物:--》动物的对象:
        //Cat c = new Cat();
        //Dog d = new Dog();
        Pig p = new Pig();
        Animal an = p;
        g.play(an);
    }
}

总结:

  1. 多态跟属性无关,多态指的是方法的多态,而不是属性的多态。
  2. 先有父类,再有子类 —> 继承 ;先有子类,再抽取父类 —> 泛化
  3. 什么是多态:
    多态就是多种状态:同一个行为,不同的子类表现出来不同的形态。
    多态指的就是同一个方法调用,然后由于对象不同会产生不同的行为。
  4. 多态的要素:
    一、继承: Cat extends Animal ,Pig extends Animal, Dog extends Animal
    二、重写:子类对父类的方法shout()重写
    三、父类引用指向子类对象:
Pig p = new Pig();
Animal an = p;
//合为一句话
Animal an = new Pig();

Animal an = new Pig();
左侧:编译期的类型;右侧:运行期的类型

public void play(Animal an){//Animal an = an = new Pig();
        an.shout();
    }

上面的代码,也是多态的一种非常常见的应用场合:父类当方法的形参,然后传入的是具体的子类的对象,然后调用同一个方法,根据传入的子类的不同展现出来的效果也不同,构成了多态。


内存分析:
在这里插入图片描述

2. 向下转型,向上转型

在这里插入图片描述
在这里插入图片描述
访问到eat()方法和weight属性需要转型:

public class Demo {
    //这是一个main方法,是程序的入口:
    public static void main(String[] args) {
        Pig p = new Pig();
        Animal an = p;//转型:向上转型
        an.shout();
        //加入转型的代码:
        //将Animal转为Pig类型:
        Pig pig = (Pig)an ;//转型:向下转型
        pig.eat();
        pig.age = 10;
        pig.weight = 60.8;
    }
}

对应内存:
在这里插入图片描述
思考之前的equals方法:判断是否是同一个类与转型不冲突
在这里插入图片描述

3. 简单工厂设计模式

不仅可以使用父类做方法的形参,还可以使用父类做方法的返回值类型,真实返回的对象可以是该类的任意一个子类对象
简单工厂模式的实现,它是解决大量对象创建问题的一个解决方案。将创建和使用分开,工厂负责创建,使用者直接调用即可。简单工厂模式的基本要求是:

  1. 定义一个static方法,通过类名直接调用
  2. 返回值类型是父类类型,返回的可以是其任意子类类型
  3. 传入一个字符串类型的参数,工厂根据参数创建对应的子类产品
public class Test {
    public static void main(String[] args) {
        Girl g = new Girl();
        //Cat c = new Cat();
        //Dog d = new Dog();
        //Pig p = new Pig();
        Animal an = PetStore.getAnimal("狗");
        g.play(an);
    }
}
public class PetStore {//宠物店 ---》工厂类
    //方法:提供动物
    public static Animal getAnimal(String petName){//多态的应用场合(二)
        Animal an = null;
        if("猫".equals(petName)){//petName.equals("猫") --》这样写容易发生空指针异常
            an = new Cat();
        }
        if("狗".equals(petName)){
            an = new Dog();
        }
        if("猪".equals(petName)){
            an = new Pig();
        }
        return an;
    }
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值