Java笔记:面向对象3大特性

一、封装

  • 程序设计追求 “高内聚,低耦合”
    • 高内聚:类的内部数据操作细节自己完成,不允许外部干涉;
    • 低耦合:仅暴露少量的方法给外部使用。
  • 封装(就是数据的隐藏)
    • 通常禁止直接访问一个对象中数据的实际表示,而应通过操作接口来访问,这称为信息隐藏。
  • 重点: 属性私有, get / set

1.基本演示:

首先创建了一个学生类

package com.oop;

public class Student {
    //封装大多时候针对属性,较少对方法用

    //名字
    private String name ;

    //学号
    private int id ;

    //性别
    private char sex;
//属性已私有

    //get/set 可以提供一些可以操作这个属性的方法
    //get可以获得这个数据   set 可以设置值
    public String getName(){
        return this.name;
    }
    public void setName(String name){
        this.name=name  ;
    }
    //自动生成get/set的快捷键(alt + insert)
    //演示


    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;
    }
}

之后在主类中去调用被保护的数据(private)


public class Application {

    public Application() {
    }

    public static void main(String[] args) {
        Student s1 = new Student();

        // 设置名字
        s1.setName("xiangliang");
        System.out.println(s1.getName());

       // 设置学号
        s1.setId(69518541);
        System.out.println(s1.getId());



    }
    
}

2.探究:

创建了一个Studen01类

package com.oop;

public class Student01 {
   private int age;


   public int getAge() {
       return age;
   }

   public void setAge(int age) {
       if (age>102||age<0){//这里设置了年龄上限下限
           System.out.println("keke please sit down");
           this.age=3;//乱输入就是3岁小孩喽
       }
       else {
           this.age = age;
       }

   }
}

主类中创建对象并测试

package com;

import com.oop.Student;
import com.oop.Student01;

import java.util.Scanner;

public class Application {

    public Application() {
    }

    public static void main(String[] args) {
        Student s1 = new Student();

        // 设置名字
        s1.setName("xiangliang");
        System.out.println(s1.getName());

       // 设置学号
        s1.setId(69518541);
        System.out.println(s1.getId());

        System.out.println("======================");


        //接下来探究下封装的实际作用
        Student01 xiaohong = new Student01();//开辟空间
        Scanner scanner = new Scanner(System.in);//使用交互
        xiaohong.setAge(scanner.nextInt());//用户输入
        System.out.println(xiaohong.getAge());//打印结果
        scanner.close();//关闭控制台

    }
    
}

结果1:
在这里插入图片描述
结果2:
在这里插入图片描述

3.总结

- 封装可以提高程序的安全性保护数据
- 隐藏代码的实现细节
- 统一接口
- 提高系统的可维护性
- 一定要记住 属性私有(private) get/set

二、继承

  • extands的意思是“扩展”派生类是超类的扩展
  • 继承本质是对某一批类的抽象
  • java中的类只有单继承而无多继承!!
  • 继承是类和类之间的一种关系。此外还有其他关系(依赖、组合、聚合)
  • 具有继承关系的两个类,其一为:派生类;其二为:基类
  • public class 派生类 extends 基类{}
  • 两个类之间意义上具有 “is a”关系
  • ======================================
  • 重点
    • Object
    • super
    • 方法重写

1.实例演示

创建基类Person

package com.jicheng;
//创建了一个          人         类
public class Person {
   /*几种修饰符
   public公共的
   protected受保护的
   default默认的(不写修饰符时默认为default)
   private私有的
    */
   //继承方法时一般用public
   //属性一般设为私有private
   int jinbi = 100;//default
   private int qian = 100000000;//private
   public long chaifu =100000000000000000L;//public
   public static void say() {
       System.out.println("TanLanHeiAn");
       System.out.println("??????????????????");
   }
   //私有的属性可以留一些公共的方法供派生类去调用
   public int getQian() {
       return qian;
   }

   public void setQian(int qian) {
       this.qian = qian;
   }
}

创建派生类Student(注意该类中我未放入代码)其继承于Person类

package com.jicheng;
//创建了一个             学生     类
//  人 类          包含        学生 类
//使学生类继承人类(extends继承)
public class Student extends Person{
}

创建一个运行程序的主类Application01

package com;

import com.jicheng.Student;

public class Application01 {
    public static void main(String[] args) {

        Student XiaoHei = new Student();//创建了一个学生对象小黑
        XiaoHei.say();//调用一下对象小黑所归属的学生类的基类(人类)的方法say()----------成功了。所以学生类里面虽然没东西,但是继承了人类的方法所以学生类也有say方法,只是我们看不到。
        System.out.println(XiaoHei.chaifu);//打印一下对象小黑所归属的学生类的基类(人类)的数据chaifu财富----------成功了。
//        System.out.println(XiaoHei.qian);//失败了-------无法直接调用(qian被我设置为private)
        System.out.println(XiaoHei.getQian());//成功了--------我给private的qian提供了方法getQian和setQian
    }
}

简单运行一下
在这里插入图片描述

2.查看继承关系

使用快捷键ctry+H
继承树

3.Object

  • 在java中所有的类都默认直接或间接继承Object类
  • Object的位置在java.lang

4.surper

示例:

package com.jicheng01

class Person02 {
    //创建一个无参构造器
    public Person02() {
        println "Person`s wucan"//Person的无参
    }
    //基类中定义了一个受保护的属性name
    protected String name ="00000001";
    public void print(){//定义了一个打印Person公共方法print
        System.out.println("Person");
    }

}
package com.jicheng01;

public class Student02 extends Person02{
    //构造器
    public Student02(){
        System.out.println("Student02`s wucan");//Student02的无参
    }
    private String name = "00000002";//私有属性
    public void print(){//定义了打印”学生“的方法print
        System.out.println("Student");
    }
    public  void test1(){//调用3个方法进行比较
        print();
        this.print();
        super.print();
    }

    public  void test(String name){//调用三个属性进行比较
        System.out.println(name);
        System.out.println(this.name);//this调用了当前类属性
        System.out.println(super.name);//super调用了基类属性
    }
}
package com;

import com.jicheng01.Student02;

public class Appplication02 {
    public static void main(String[] args) {
        Student02 student02 = new Student02();
        student02.test("000000003");//调用三个属性进行比较
        student02.test1();//调用3个方法进行比较
    }
}

结果:
在这里插入图片描述
结论:

  1. super的注意事项

    • super若想调用基类的构造方法,位置必须在构造方法的第一个
    • super只能出现在派生类的方法或构造方法中
    • super和this不能同时调用构造方法

    另外

    this调用自身
    super是对基类的引用

  2. 在子类的构造方法中

    编译器会自动在子类构造函数的第一句加上 super(); 来调用父类的无参构造器;此时可以省略不写。如果想写上的话必须在子类构造函数的第一句,可以通过super来调用父类其他重载的构造方法,只要相应的把参数传过去就好。
    
    因此,super的作用主要在下面三种情况下:
    
    - 调用父类被子类重写的方法;
    
    - 调用父类被子类重定义的字段(被隐藏的成员变量);
    
    - 调用父类的构造方法;其他情况,由于子类自动继承了父类相应属性方法,关键字super可以不显示写出来。
    

5.方法的重写

  • 重写只针对方法,和属性无关

代码一组:

package chongxie.Deom.ChongXie01;
//重写只针对方法,和属性无关
public class B {
    public static void test(){
        System.out.println("B=>test()");
    }
}
package chongxie.Deom.ChongXie01;

public class A extends B{
    public static void test(){
        System.out.println("A=>test()");
    }
}
package chongxie.Deom;

import chongxie.Deom.ChongXie01.A;
import chongxie.Deom.ChongXie01.B;

public class Application {
    public static void main(String[] args) {
        //方法的调用只和左边的数据类型有关
        A a = new A();
        a.test();
        //基类的引用指向派生类
        B b = new A();
        b.test();
    }
}

结果:
在这里插入图片描述

组二:

在这里插入图片描述
(我去掉一个static后会报错。。无论是基类还是派生类)同时去掉2个static不会报错。

在这里插入图片描述
之后我将其注释,加入新的重写
在这里插入图片描述

组三 重写方法的代码

package chongxie.Deom.ChongXie01;
//重写只针对方法,和属性无关
public class B {
    public  void test(){
        System.out.println("B=>test()");
    }
}
package chongxie.Deom.ChongXie01;

public class A extends B{
//    public  void test(){
//        System.out.println("A=>test()");
//    }

    //Override翻译:(函数覆盖;复盖;覆盖;重写;重载)
    @Override//自动生成的注解(有功能的注释)
    public void test() {
//        super.test();//其默认调用的父类方法(我们可以去写自己的方法)
        System.out.println("A=>test()");
    }
}
package chongxie.Deom;

import chongxie.Deom.ChongXie01.A;
import chongxie.Deom.ChongXie01.B;

public class Application {
    public static void main(String[] args) {
        //方法的调用只和左边的数据类型有关
        A a = new A();
        a.test();
        //基类的引用指向派生类
        B b = new A();
        b.test();
    }
}

我的Application类未做任何更改。。。接下来看看运行结果
在这里插入图片描述

思考与总结:

  1. 方法静态与非静态有巨大区别

  2. 派生类可以重写基类的方法(重写与非静态有关)

  3. 重写需要有public关键词,使用private关键词无法重写

  4. 方法重载在本身类中实现,方法重写在继承类中实现。

  5. 实现重写时注意点:

    • 方法名相同
    • 参数列表必须相同
    • 修饰符:范围可以扩大但不可缩小 (public>protected>default>private)
    • 抛出的异常:范围可以缩小但不可扩大(ClassNotFoundExcepsion)
    • 派生类和基类的方法要一致;而方法体不同。
  6. 为什么需要重写:

    基类的功能 派生类不一定需要 或 不一定满足

三、多态

概念:
方法的重写、重载与动态连接构成多态性

目的:(Java之所以引入多态的概念,原因之一就它在类的继承上的问题和C++不同,后者允许多继承,这确实给其带来了非常强大的功能,但是复杂的继承关系也给C++开发者带来了更大的麻烦,为了规避风险,Java只允许单继承,势必在功能上有很大的限制,所以,Java引入多态性的概念以弥补这点不足,此外,抽象类和接口也是解决单继承规定限制的重要手段.同时,多态也是面向对象编程的精髓所在.)

特性:

  • 同一个方法可以根据发送的对象不同而采用多种不同的行为方式。

  • 一个对象的实际类型是确定的,但可以指向对象的引用类型有很多

  • 多态存在的条件:

    • 有继承关系
    • 子类重写父类方法
    • 父类引用指向子类对象
  • 注意点:

    • 方法有多态

    • 属性无多态

  • instanceof

1.试验探究演示一:

父类:

package com01.duotai.deomo;

public class Person {
    public void say(){
        System.out.println("ShuoHua");//说话
    }
}

子类:

package com01.duotai.deomo;

public class Student extends Person{
    public void say(){
        System.out.println("ChangGe");//唱歌
    }
}

主类:

package com01.duotai;

import com01.duotai.deomo.Person;
import com01.duotai.deomo.Student;

public class Application {
    public static void main(String[] args) {
        //一个对象的实际类型是确定的
//        new Student();//学生类
//        new Person();//人类
        //但可以指向的引用类型却不一定确定(父类的引用可以指向子类)
        Student xiaoliang = new Student();//创建对象:小亮。类型:Student。
        Person xiaohei = new Student();//创建对象:小黑。类型:Student。
        Object xiaoqing = new Student();//创建对象:小青。类型Student。
        xiaoliang.say();
        xiaohei.say();
//        xiaoqing.say();

    }
}

结果
在这里插入图片描述
思考:为什么xiaohei的引用类是Person类(父类)但会调用子类的重写方法?(注意:这些对象全由new Student创建)什么是父类引用?

2.试验探究演示二:

还以Person为父类,创建子类Oldman

package com01.duotai.deomo;

public class Oldman extends Person{
    public void say1(){
        System.out.println("Tanqi");//叹气
    }
}

主类去调用

package com01.duotai;

import com01.duotai.deomo.Oldman;
import com01.duotai.deomo.Person;
import com01.duotai.deomo.Student;

public class Application {
    public static void main(String[] args) {
        //一个对象的实际类型是确定的
//        new Student();
//        new Person();
        //但可以指向的引用类型却不一定确定(父类的引用可以指向子类)
        Student xiaoliang = new Student();//创建对象:小亮。引用类型:Student。
        Person xiaohei = new Student();//创建对象:小黑。引用类型:Person。
        Object xiaoqing = new Student();//创建对象:小青。引用类型Object。

        xiaoliang.say();//say方法被重写,所以执行子类方法say。
        xiaohei.say();//同样执行子类方法say
//        xiaoqing.say();会报错。。。不可以这么写


        Oldman old1 = new Oldman();//创建对象:old1。引用类型:Oldman。
        Person old2 = new Oldman();//创建对象:old2。引用类型:Person。
        old1.say1();
//        old2.say1();//old2无法调用子类Oldman的方法say1()

    }
}

结果:
在这里插入图片描述

old2.say1();根本无法被创建,毕竟Person中都没写say1方法

可以发现一些规律:

 1. 若:父类有方法A(){b},子类无方法,主类中创建一个子类型对象; 则:主类可以调用子类继承父类所得的方法A(){b}

 2. 若:父类有方法A(){b},子类有方法A(){c},主类中创建一个子类型对象; 则:主类可以调用子类重写父类方法A(){b}所得的方法A(){c} 

 3. 若:父类无方法,子类有方法A(){b},主类中创建一个父类型对象; 则:主类不可以调用子类的独有方法A(){b}。

重点:

 4. 若:父类有方法A(){b},子类有方法A(){c},主类中创建一个引用父类型指向子类型对象; 则:主类可以调用子类重写父类方法A(){b}所得的方法A(){c}         即所谓:动态链接

根据我的理解:
我们可以创建一主类,一父类,多子类。父类中提前写好一些基本的属性和方法,然后子类可以继承父类的属性和方法;并且子类中可以有一些自己独有的属性和方法使其功能更强大,而在实例化不同子类对象时,提前有多个不同子类可以对同一个父类的同一个方法进行重写,使得对象调用方法时更加灵活。

大体如此,我学的速度可能有点过快,许多知识还没彻底理解;多态的部分概念以及拓展知识后面再进行补充;自己会先复习巩固一下。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值