欢迎来到 Kong Xiangqun 的博客

10-封装\继承\抽象类、抽象方法\final用法

一、封装

1、狭义的封装

public class Dog {

    private String name;
    private int age;
    private String color;

    public Dog(){

    }

    public Dog(String name,int age,String color){
        this.name = name;
        // if(age>0){
        //    this.age = age;
        // }else{
        //     System.out.println("年龄不规范");
        // }
        this.age = age;
        this.color = color;
    }

    public void eat(){
        System.out.println("eating 骨头");
    }

    public void play(){
        System.out.println("palying....");
    }

    public void show(){
        System.out.println("name:"+this.name);
        System.out.println("age:"+this.age);
        System.out.println("color:"+this.color);
    }

}
public class DogTest {
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.name="大黄";
        dog.setAge(-20);
        // dog.setAge(20);
        dog.color="yellow";
        dog.show();
    }
}

结果能正常打印, 但是年龄不能为负

可以通过构造方法加判断

/*
* 封装:
*       概念:
*           将类的某些信息隐藏在类内部,不允许外部程序直接访问,
*           而是通过该类提供的方法来实现对隐藏信息的操作和访问
*       封装解决什么问题:
 *          如果任何一个处理类都可以直接对Dog进行赋值操作,那么当值不准确的时候,可能会产生额外的结果,
*           如何在赋值的同时添加一些逻辑判断呢?
*               封装可以解决此问题
*       作用:
*           使用封装可以保证数据的规范,不符合规范的数据将无法进行操作
*       好处:
*           1、隐藏类的内部实现细节
*           2、只能通过提供的方法进行访问,其他方法无法访问
*           3、可以根据需求添加复杂的逻辑判断语句
*           4、方便修改实现
*       面向对象的封装(狭义)可以用一句话概述: 为了保证数据安全和规范
*           将类中的属性设置为私有属性,提供共有的外部方法供程序进行调用,可以实现丰富的细节操作
*       广义的封装:
*           可以将完成特定功能的代码块封装成一个方法,供不同的程序进行调用
* */
public class Dog {

    private String name;
    private int age;
    private String color;

    public Dog(){

    }

    public Dog(String name,int age,String color){
        this.name = name;
        if(age>0){
            this.age = age;
        }else{
            System.out.println("年龄不规范");
        }
        this.color = color;
    }

    public void setAge(int age){
        if(age>0){
            this.age = age;
        }else{
            System.out.println("输入年龄不规范,重新输入");
        }
    }

    public int getAge(){
        return this.age;
    }

    public void setName(String name){
        this.name = name;
    }

    public String getName(){
        return this.name;
    }

    public void setColor(String color){
        this.color = color;
    }

    public String getColor(){
        return this.color;
    }


    public void eat(){
        System.out.println("eating 骨头");
    }

    public void play(){
        System.out.println("palying....");
    }

    public void show(){
        System.out.println("name:"+this.name);
        System.out.println("age:"+this.age);
        System.out.println("color:"+this.color);
    }

}
public class DogTest {
    public static void main(String[] args) {
        Dog dog = new Dog();
//        dog.name="大黄";
//        dog.setAge(-20);
        dog.setAge(20);
//        dog.color="yellow";
//        dog.show();
        System.out.println(dog.getAge());
    }
}

2、广义的封装

可以将完成特定功能的代码块封装成一个方法,供不同的程序进行调用

3、访问控制符

使用访问控制符,实现封装
▪成员(成员变量戒成员方法)访问权限共有四种:
  –public 公共的
    ▪可以被项目中所有的类访问。(项目可见性)
  –protected 受保护的
    ▪可以被这个类本身访问;同一个包中的所有其他的类访问;被它的子类(同一个包以及丌同包中的子类)访问
  –default/friendly 默认的/友好的(包可见性)
    ▪被这个类本身访问;被同一个包中的类访问。
  –private 私有的
    ▪只能被这个类本身访问。(类可见性)
▪类的访问权限只有两种
  –public 公共的
    ▪可被同一项目中所有的类访问。 (必须不文件名同名)
  –default/friendly 默认的/友好的
    ▪可被同一个包中的类访问。
测试一下
在项目src下创建包com.kxq
/*
* 在java中明确定义了访问权限:
*          限制访问,以下分类按照从大到小进行排列
*       public:公共的
*           当前项目的所有的类都可以进行访问
*       protected:受保护的
*           可以被当前类访问,可以被当前包访问,也可以被子类访问
*       default:默认权限
*           可以被当前类访问,可以被当前包访问,
*       private:私有权限
*           只能被当前类访问
*
*       注意:四种访问修饰符可以修饰属性和方法
*       类的访问修饰符只有两个  public default
*
* */
// 一个文件中可以有多个类,但只能有一个public class, 其他都是default
public class AccessControlDemo { public AccessControlDemo(){ } // 单例设计模式 protected AccessControlDemo(int a,int b){ } private String str = "test"; // 修饰符分别为public protected default private } class Test{ }

在src下创建Test.java 文件

当修饰符为public时,当前项目所有类都可以访问

package src;

import com.mashibing.AccessControlDemo;

public class Test {
    public static void main(String[] args) {
        AccessControlDemo acd = new AccessControlDemo();
        System.out.println(acd.str);
    }
}

打印结果为:

/*
test

Process finished with exit code 0
*/

当修饰符为protected时,可被当前类\子类\当前包访问, 此文件不在包中

程序中已经报错了

如果在当前包下面创建一个Test.java文件,就可以访问的到

当为default, 也就是不用写修饰符时, 可被当前类\当前包访问, 子类访问不了

 

当为private, 只能当前类访问

 

 

 4、方法调用中的参数传递

4.1、基本数据类型传递

/*
*
* 方法参数的值是否改变
*       方法中的参数列表叫做形式参数,没有具体的值,只是为了方便在方法体中使用
*       调用方法的时候实际传入的值叫实际参数,代表具体的数值,用来替换在方法体中代码逻辑的值进行运算
*       注意:
*           1、形式参数的变量名称也是局部变量
*           2、当方法的参数值是基本数据类型的时候,不会改变原来的值
*           3、当方法的参数值是引用类型的时候,如果改变了该引用类型的值,会改变原来对象的值
*       java中的参数传递是值传递
* */
public class ArgumentDemo {

    public static void test(int a,int b){
        int tmp = a;
        a = b;
        b = tmp;
    }

    public static void main(String[] args) {
        int a = 10;
        int b = 20;
        test(a,b);
        System.out.println(a);
        System.out.println(b);
    }
}

打印结果值并不会调换

内存区

 

 在函数里面确实 a和b已经交换了,但是在函数外面指向的是main中的a, b, 还是a=10; b=20;所以值是没变的

4.2、引用类型传递

public class ArgumentDemo {

    public static void test(int a,int b){
        int tmp = a;
        a = b;
        b = tmp;
    }

    public static void test2(Point point){
        int x = point.getX();
        int y = point.getY();
        int tmp = x;
        x = y;
        y = tmp;
        point.setX(x);
        point.setY(y);
    }



    public static void main(String[] args) {
//        int a = 10;
//        int b = 20;
//        test(a,b);
//        System.out.println(a);
//        System.out.println(b);
        Point point = new Point(2,3);
        test2(point);
        System.out.println(point.getX());
        System.out.println(point.getY());
    }
}

 

public class Point {
    private int x;
    private int y;

    public int getX() {
        return x;
    }

    public void setX(int x) {
        this.x = x;
    }

    public int getY() {
        return y;
    }

    public void setY(int y) {
        this.y = y;
    }

    public Point(int x, int y){
        this.x = x;
        this.y = y;
    }

}

 

5、练习

5.1、练习1-设计DOG和Penguin类

/*
▪ 需求说明:
– 运用面向对象思想抽象出Dog类和Penguin类,画出对应类图
– 根据类图编写Dog类和Penguin类 
– 添加默认构造方法
*/

 

5.2、练习2-打印Dog信息

/*
▪ 需求说明:
– 根据控制台提示信息选择领养宠物(狗),
▪ 输入昵称、品种、健康值
▪ 打印宠物信息
– 要保证健康值的有效性(在1到100乊间)
*/

 

 

5.3、练习3-Dog类的带参构造方法

/*
▪ 需求说明:
– 增加带参构造方法
– 修改Test类,使用带参构造方法创建对象
*/

 

5.4、练习4-操作企鹅性别属性

/*
▪ 需求说明:
– 给Penguin类提供SEX_MALE和SEX_FEMALE两个静态常量,
分别取值“Q仔”戒“Q妹”
– 修改Test类,使用静态常量对性别进行赋值
– 修改企鹅的性别只能取值“雄”戒“雌”,通过修改静态变量实现该
需求
*/

 

二、继承

/*
* 继承:
*   表示父类跟子类之间的关系
*   当两个类或者多个类具备相同的属性和方法的时候,可以提取出来,变成父类,子类可以继承
*
*   子类跟父类是is-a的关系
*
*   使用:
*       1、使用继承的时候需要使用extend关键字
*       2、使用继承关系之后,父类中的属性和方法都可以在子类中进行使用(非私有属性和非私有方法)
*       3、java中是单继承关系(如果包含多个父类,同时父类中包含重名方法,无法决定改调用谁)
*
*
* super:是 直接父类 对象的引用
*   用途:
*       1、可以在子类中调用父类中被子类覆盖的方法  super.父类方法名称 也就是子类和父类方法同名但想要在子类中调用的是父类中的方法可以用super()
*       2、当super在普通方法中使用的话,可以任意位置编写
*       3、当super在构造方法中使用的话,会调用父类的构造方法,一定要将super放在第一行
*       4、在构造方法中super关键字和this关键字不能同时出现
*       5、父类中私有的属性和方法都不能被调用,包括构造方法
*       6、子类的构造方法中都会默认使用super关键字调用父类的无参构造方法,因此在定义类的时候,无论自己是否自定义了
*               其他构造方法,最好将无参构造方法写上
*       7、如果构造方法中显式的指定了super的构造方法,那么无参的构造方法就不会被调用
*
*   总结:
*       1、在创建子类对象的时候一定会优先创建父类对象
*       2、所有的java类都具备同一个老祖宗类,称之为Object,是所有类的根类
*
* 重写:
*   必须要存在继承关系,当父类中的方法无法满足子类需求的时候可以选择使用重写的方式
*   注意:
*       1、重写表示的是子类覆盖父类的方法,当覆盖之后,调用同样的方法的时候会优先调用子类
*       2、重写的方法名称,返回值类型,参数列表必须跟父类一直
*       3、子类重写的方法不允许比父类的方法具备更小的访问权限
*           父类      public     子类  public
*           父类      protected     子类  public protected
*           父类      default     子类  public protected  default
*   父类的静态方法子类可以进行调用,但是子类不可以重写
* */

 

public class Pet {

    private String name;
    private int age;
    private String gender;
    protected String abc;

    public Pet(){
        System.out.println("pet 无参构造方法");
    }

    public Pet(String name, int age, String gender) {
//        this();
        this.name = name;
        this.age = age;
        this.gender = gender;
    }

    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 String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }
}

 

public class Dog extends Pet{

//    private String name;
//    private int age;
//    private String gender;
    private String sound;

    public Dog(){
        System.out.println("dog 无参构造");
    }

    public Dog(String name, int age, String gender, String sound) {
        super(name,age,gender); // 在上在下没关系
        this.sound = sound;
    }
    
//    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 String getGender() {
//        return gender;
//    }
//
//    public void setGender(String gender) {
//        this.gender = gender;
//    }
}

 

public class Penguin extends Pet{

//    private String name;
//    private int age;
//    private String gender;
    private String color;

    public Penguin(){

    }

    public Penguin(String name, int age, String gender, String color) {
//        this.name = name;
//        this.age = age;
//        this.gender = gender;
        super(name,age,gender);
        this.color = color;
    }
}
public class PetTest {

    public static void main(String[] args) {

        Dog dog = new Dog("小黑",12,"男","汪汪");
        dog.setName("大黄");
        System.out.println(dog.getName());
    }
}

打印结果为:

// 大黄

 

 super()的用法

public class Pet {

    private String name;
    private int age;
    private String gender;
    protected String abc;

    public Pet(){
        System.out.println("pet 无参构造方法");
    }

    public Pet(String name, int age, String gender) {
//        this();
        this.name = name;
        this.age = age;
        this.gender = gender;
    }
    ...
    ...
    ...
    private void play(){
        System.out.println("play.....");
    }
}
public class Dog extends Pet{

//    private String name;
//    private int age;
//    private String gender;
    private String sound;

    public Dog(){
        System.out.println("dog 无参构造");
    }

    public Dog(String name, int age, String gender, String sound) {
//        super(name,age,gender);
        this.sound = sound;
    }
    ...
    ...
    ...
    public void play(){
        super.play();
        System.out.println("dog is playing ball");
    }
public class PetTest {

    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.play();
    }
}

打印结果为

/*
大黄
play.....
dog is playing ball
*/

 

2.1、重写

 重载表示同一个类中包含了多个同名的方法, 但是这些同名方法的列表是不同的, 个数不同、类型不同、顺序不同, 这种叫重载, 重写与重载没有关系

public class Pet {

    private String name;
    private int age;
    private String gender;
    protected String abc;

    public Pet(){
        System.out.println("pet 无参构造方法");
    }

    public Pet(String name, int age, String gender) {
//        this();
        this.name = name;
        this.age = age;
        this.gender = gender;
    }
    ...
    ...
    ...
    //    @Override
    //    public String toString(){
    //        return "my name is "+this.name+",my age is         "+this.age+",my gender is"+this.gender;
   //    }
}

 

public class PetTest {

    public static void main(String[] args) {
        Pet pet = new Pet();
        System.out.println(pet);
    }
}

打印结果为:

/*
pet 无参构造方法
com.mashibing.extend.Pet@1b6d3586

Process finished with exit code 0
*/

包名加完全限定名 地址

把父类的注释打开, 重写toString()

打印结果为:

/*
pet 无参构造方法
my name is null,my age is 0,my gender isnull

Process finished with exit code 0
*/

 

public class Dog extends Pet{

//    private String name;
//    private int age;
//    private String gender;
    private String sound;

    public Dog(){
        System.out.println("dog 无参构造");
    }

    public Dog(String name, int age, String gender, String sound) {
//        super(name,age,gender);
        this.sound = sound;
    }
    ...
    ...
    ...
    public void play(){
        System.out.println("dog is playing ball");
//        super.play();
    }


    public String toString(){
        return super.toString()+",my sound is"+this.sound;
    }    

Dog里面还有一个sound属性, 父类Pet打印的时候把sound也加进去, 此时要修改父类方法, 意味着父类无法满足子类的需要

public class PetTest {

    public static void main(String[] args) {
        Pet pet = new Pet();
        System.out.println(pet);
        Dog dog = new Dog();
        System.out.println(dog);
    }
}

打印结果为:

/*
pet 无参构造方法
my name is null,my age is 0,my gender isnull
pet 无参构造方法
dog 无参构造
my name is null,my age is 0,my gender isnull,my sound isnull

Process finished with exit code 0
*/

方法重写与重载

 

静态方法能被继承吗? 能被重写吗?

public class Pet {

    private String name;
    private int age;
    private String gender;
    protected String abc;

    public Pet(){
        System.out.println("pet 无参构造方法");
    }

    public Pet(String name, int age, String gender) {
//        this();
        this.name = name;
        this.age = age;
        this.gender = gender;
    }
    ...
    ...
    ...
    public static void test(){
        System.out.println("static test");
    }
}
public class PetTest {

    public static void main(String[] args) {
        Dog dog = new Dog();
        System.out.println(dog);
        dog.test();
    }
}

打印结果为:

/*
static test
*/

静态方法可以被继承

不能被重写

三、抽象类\抽象方法

 某些类不具备实例化的含义, 狗是宠物, 猫是宠物, ,宠物是宠物吗? 所以宠物这个类是不具备实例化的

java中使用抽象类, 限制实例化

public abstract class Pet {

}
/*
* java中的对象是对现实世界的具象化,但是在现实世界中,某些类并不具备实例化的意义,因此可以定义为抽象类
*
* 抽象类:
*       1、创建抽象类的时候需要添加 abstract 的关键字
*       2、不能进行实例化,也就是不能new对象
*       3、抽象类中的某些方法需要子类进行更丰富的实现,父类实现没有意义,此时可以将抽象类
*             中的方法定义为抽象方法,没有具体的实现,只包含方法名称,返回值,参数列表,访问修饰符
*       4、使用abstract关键字修饰的方法叫做抽象方法,可以不写方法的实现
*       5、子类在继承抽象父类的时候,必须要将父类中的抽象方法进行实现或者将子类也定义为抽象类
*       6、有抽象方法的一定是抽象类,但是抽象类中不一定包含抽象方法
* */
public abstract class Pet {

    private String name;
    private int age;

    public abstract void print();

    public void play(){
        System.out.println("play....");
    }

}
public class Dog extends Pet{
    private String gender;

    @Override
    public void print() {
        System.out.println("dog print");
    }
}
public class  AbstractTest {
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.print();
        dog.play();
    }
}

四、final用法

/*
* final的使用:
*       final可以修饰变量:
*               表示变量的值不可变
*       final可以修饰方法:
*               表示方法不可以被重写
*       final可以修饰类:
*               表示类不可以被继承
*
* */
public final class FinalDemo {

    public final  String name = "zhangsan"; // 其他语言可能有constant
    public final void test(){
        System.out.println("final test");

    }

    public static final int age =10;
    
    public static void main(String[] args) {
//        age = 20;
    }
}
public class FinalSubClass /* extends FinalDemo*/{

//    @Override
//    public final void test(){
//
//    }
}

 

 

五、Object

1、==和equals()

▪ ==:
  – 比较两基本类型变量的值是否相等
  – 比较两个引用类型的值即内存地址是否相等,即是否指向同一对象。
▪ equals() :
  – 两对象的内容是否一致
▪ 示例
  – object1.equals(object2) 如:p1.equals(p2)
    ▪ 比较所指对象的内容是否一样
    ▪ 是比较两个对象,而非两个基本数据类型的变量
  – object1 == object2 如:p1==p2
    ▪ 比较p1和p2的值即内存地址是否相等,即是否是指向同一对象。
▪ 自定义类须重写equals(),否则其对象比较结果总是false。
练习:
/*
▪某汽车租赁公司出租多种车辆,车型及租金情况如下:
▪编写程序实现计算租赁价
*/

分析:

▪发现类

 

 

▪发现类的属性

 

 

public abstract class MotoVehicle {

    private int no; // 车牌号
    private String brand; // 品牌

    public MotoVehicle(){

    }

    public MotoVehicle(int no,String brand){
        this.no = no;
        this.brand = brand;
    }

    public int getNo() {
        return no;
    }

    public void setNo(int no) {
        this.no = no;
    }

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }

    // 计算租金
    public abstract int calcRent(int day);
}

 

public class Car  extends MotoVehicle{

    private String type; // 型号

    public Car(){

    }

    public Car(String type) {
        this.type = type;
    }

    public Car(int no,String brand,String type){
        super(no,brand);
        this.type= type;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    @Override
    public int calcRent(int day) {

        if(type.equals("0")){
            return 600*day;
        }else if(type.equals("1")){
            return 500*day;
        }else if(type.equals("2")){
            return 300*day;
        }else{
            System.out.println("类型不匹配");
            return 0;
        }
    }
}

 

public class Bus extends MotoVehicle {

    private int seatcount; // 几座

    public Bus(){

    }

    public Bus(int no,String brand,int seatcount){
        super(no,brand);
        this.seatcount = seatcount;
    }

    public int getSeatcount() {
        return seatcount;
    }

    public void setSeatcount(int seatcount) {
        this.seatcount = seatcount;
    }

    @Override
    public int calcRent(int day) {
        if(seatcount>16){
            return 1500*day;
        }else{
            return 800*day;
        }
    }
}

 

public class TestMotoVehicle {
    public static void main(String[] args) {
//        MotoVehicle moto = new MotoVehicle(); // 可以有构造方法,但是不能实例化
        Car car = new Car(1,"宝马","1");
        System.out.println("租金是:"+car.calcRent(5));
        Bus bus = new Bus(2,"金龙",20);
        System.out.println("租金是:"+bus.calcRent(5));
    }
}

打印结果为:

/*
租金是:2500
租金是:7500

Process finished with exit code 0
*/

 

 

 

posted @ 2022-04-25 21:10  kongxiangqun20220317  阅读(65)  评论(0编辑  收藏  举报