面相对象中级(包、访问修饰符、封装、继承、super关键字)

一、包

1.1包的基础概念

1.2包的本质

包的本质实际上就是创建不同的文件夹来保存类文件,示意图如下:

  

                      

包就是两个文件夹,同一个包下方法的名称不能相同,但不同包下方法的名称可以相同。虽然名称相同,但这可以是两个完全不相同的类。

1.3包的基本代码

引入包

package com.use;

import com.baostudy.Dog;

public class test {
    public static void main(String[] args) {
        Dog dog = new Dog();
        com.modifierStudy.Dog dog1 = new com.modifierStudy.Dog();
        /*
           为了区分两个dog,下面的用包名进行区分
           本质用途还是一样的。
        */
    }
}

一些常见的包

1.4包的相关细节

二、访问修饰符

2.1访问修饰符的基本概念

2.2访问修饰符的相关细节

三、封装

3.1封装的基础概念

封装就是把抽象出的数据[属性]和对数据的操作[方法]封装在一起,数据被保护在内部,程序其它部分只有通过被授权的操做[方法],才能对数据进行操作。(电视机就是一个例子,开关电视机在电视机内部是一个非常复杂的过程,但对于用户来说只需要按一下开关键。用户无法改变内部结构。)

3.2封装的实现

3.3封装的实例代码

要求如下:

package com.ssj.encap;

public class Encapsulation01 {
    public static void main(String[] args) {
        Person person = new Person();
        person.setName("jack");
        person.setSalary(30000);
        person.setAge(30);
        System.out.println(person.name);
        //工资和年龄只有通过get才能查到,不能直接查到
        //可以在get上增加一些逻辑比如:密码。才能查询
        person.getSalary("admin");
        person.getAge("aaaaa");
    }
}
class Person{
    public String name;
    private int age;
    private double salary;
    //自己写setxxx和getxxx太慢了,使用快捷键。
    //alt+insert选择(Getter and Setter)
    //然后根据要求完善代码
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public void getAge(String lock) {
        if(lock == "admin") {
            System.out.println(age);
        }
        else{
            System.out.println("密码错误,没有权限访问年龄");
        }
    }
    public void setAge(int age) {
        if (age >= 1 && age <= 120) {
            this.age= age;
        }
        else{
            System.out.println("你设置的年龄不对,年龄需要在 1-120 ,给你默认年龄18");
            this.age = 18;
        }
    }
    public void getSalary(String lock) {
        if(lock == "admin") {
            System.out.println(salary);
        }else{
            System.out.println("密码错误,没有权限访问工资");
        }
    }
    public void setSalary(double salary) {
        this.salary = salary;
    }
}

由上可知封装的好处:1.可以隐藏实现细节2.可以对数据进行验证(set方法),保证安全合理(在get中增加逻辑)。

上述代码有个问题,因为在实际应用的过程中会顺手写构造器,以便随时能用。(就不用一个参数一个set方法了)如果使用构造器进行赋值的话就可以绕过set方法,这样就不能验证了。解决代码如下:

 public Person(String name, int age, double salary) {
        this.name = name;
        this.age = age;
        this.salary = salary;
        setSalary(salary);
        setName(name);
        setAge(age);
    }

在构造器中调用set方法就可以避免这个问题了。

package com.ssj.encap;

public class Encapsulation01 {
    public static void main(String[] args) {
        Person person = new Person("jack",30,30000);
        System.out.println(person.name);
        person.getSalary("admin");
        person.getAge("aaaaa");
        //工资和年龄只有通过get才能查到,不能直接查到
        //可以在get上增加一些逻辑比如:密码。才能查询
    }
}
class Person{
    public String name;
    private int age;
    private double salary;
    //自己写setxxx和getxxx太慢了alt+insert
    //选择(Getter and Setter)
    //然后根据要求完善代码
    public Person(String name, int age, double salary) {
        this.name = name;
        this.age = age;
        this.salary = salary;
        setSalary(salary);
        setName(name);
        setAge(age);
    }

    public String getName() {
        return name;
    }

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

    public void getAge(String lock) {
        if(lock == "admin") {
            System.out.println(age);
        }
        else{
            System.out.println("密码错误,没有权限访问年龄");
        }
    }

    public void setAge(int age) {
        if (age >= 1 && age <= 120) {
            this.age= age;
        }
        else{
            System.out.println("你设置的年龄不对,年龄需要在 1-120 ,给你默认年龄18");
            this.age = 18;
        }
    }
    public void getSalary(String lock) {
        if(lock == "admin") {
            System.out.println(salary);
        }else{
            System.out.println("密码错误,没有权限访问工资");
        }
    }

    public void setSalary(double salary) {
        this.salary = salary;
    }
}

四、继承

4.1继承的基础概念

先看两段代码;

package com.extend;
//大学生考试
public class Graduate {
    public String name;
    public int age;
    private double score;

    public void setScore(double score) {
        this.score = score;
    }
    public void testing(){
        System.out.println(" 大学生 " + name + " 正在考大学数学 ");
    }
    public void showInfo(){
        System.out.println(" 学生名 " + name + " 年龄 " + age + " 成绩 " + score);
    }
}
package com.extend;
//小学生考试
public class pupil {
    public String name;
    public int age;
    private double score;

    public void setScore(double score) {
        this.score = score;
    }
    public void testing(){
        System.out.println(" 小学生 " + name + " 正在考小学数学 ");
    }
    public void showInfo(){
        System.out.println(" 学生名 " + name + " 年龄 " + age + " 成绩 " + score);
    }
}

通过看上述两段代码不难发现,代码中有很多重复的部分也有不重复的部分,对于重复部分其实是学生的共有属性,重复写很麻烦,可以采取继承的方式解决这一问题。

4.2继承的基本代码

对于开头的代码运用继承进行优化。

父类:

package com.extend.improve_;
//父类:是pupil和graduate的父类
public class student {
    //共有属性
    public String name;
    public int age;
    private double score;
    //共有方法
    public void setScore(double score) {
        this.score = score;
    }
    public void showInfo(){
        System.out.println(" 学生名 " + name + " 年龄 " + age + " 成绩 " + score);
    }
}

子类: 

package com.extend.improve_;

public class pupile extends student{
    public void testing(){
        System.out.println(" 小学生 " + name + " 正在考小学数学 ");
    }
}
package com.extend.improve_;

public class Graduate extends student{
    public void testing(){
        System.out.println(" 大学生 " + name + " 正在考大学数学 ");
    }
}

主函数 

package com.extend.improve_;

public class Extends01 {
    public static void main(String[] args) {
        pupile pupile = new pupile();
        pupile.name = "银角大王";
        pupile.age = 10;
        pupile.testing();
        pupile.setScore(60);
        pupile.showInfo();
        System.out.println("========");
        Graduate graduate = new Graduate();
        graduate.name = "金角大王";
        graduate.age = 22;
        graduate.testing();
        graduate.setScore(100);
        graduate.showInfo();
    }
}

4.3继承的本质

4.4继承的相关细节 

(1)子类继承了所有的属性和方法,但是私有(private)属性和方法不能在子类直接访问,要通过父类提供公共的方法去访问。

private int name = 10;
public void getName{
    System.out.println(name)
}
private void test400(){
    System.out.println("test400");
}
    
public void getTest400(){
     test400();
}

(2)子类必须调用父类的构造器,完成父类的初始化。

(3)当创建子类对象时,不管使用子类的哪个构造器,默认情况下总会去调用父类的无参构造器,如果父类没有提供无参构造器,则必须在子类的构造器中使用super去指定使用父类的哪个构造器完成对父类的初始化工作,否则,编译不会通过。[对于上面这段话可以一句一句去理解]

当创建子类对象时,不管使用子类的哪个构造器,默认情况下总会去调用父类的无参构造器

package com.extend.improve_;


public class Sub extends Base {
    public Sub(){
        //super()默认调用父类的无参构造器
        System.out.println("子类sub()构造器被调用");
    }
    //当创建子类对象时,不管使用子类的哪个构造器,默认情况下总会去调用父类的无参构造器
    public Sub(String name){
        System.out.println("子类Sub()构造器被调用");
    }
    public void sayOk(){
        //非私有的属性和方法可以在子类直接访问
        //但是私有属性和方法不能在子类直接访问
        System.out.println(n1+" "+n2+" "+n3);
        test100();
        test200();
        test300();
    }
}
package com.extend.improve_;

public class Base {
    public int n1 = 100;
    protected int n2 = 200;
    int n3 = 300;
    private int n4 = 400;

    public Base(){
        System.out.println("父类Base()构造器被调用");
    }
    public int gtN4(){
        return n4;
    }
    public void test100(){
        System.out.println("test100");
    }
    protected void test200(){
        System.out.println("test200");
    }
    void test300(){
        System.out.println("test300");
    }
    private void test400(){
        System.out.println("test400");
    }

    public void getTest400(){
        test400();
    }
}
package com.extend.improve_;

public class extemdsDetail {
    public static void main(String[] args) {
        Sub sub = new Sub();//创建一个子类对象
        System.out.println("===第二个对象===");
        Sub sub1 = new Sub("jack");
    }
}

                         

通过上述代码及其运行结果可以看出,只调用了子类的构造器,父类的构造器也被调用了。

如果父类没有提供无参构造器,则必须在子类的构造器中使用super去指定使用父类的哪个构造器完成对父类的初始化工作,否则,编译不会通过。

 因为子类中的super()默认(super是隐含存在的,只是编译器自带的)调用父类的无参构造器,而父类没有加无参构造器,因此代码报错。解决办法:

package com.extend.improve_;


public class Sub extends Base {
    public Sub(){
        super("smith",10);
        System.out.println("子类sub()构造器被调用");
    }
    //当创建子类对象时,不管使用子类的哪个构造器,默认情况下总会去调用父类的无参构造器
    public Sub(String name){
        super("tom",30);//因为父类中没有无参构造器
                        //需要super去指定调用父类的哪一个构造器
        System.out.println("子类Sub()构造器被调用");
    }
    public void sayOk(){
        //非私有的属性和方法可以在子类直接访问
        //但是私有属性和方法不能在子类直接访问
        System.out.println(n1+" "+n2+" "+n3);
        test100();
        test200();
        test300();
    }
}

(4)如果希望指定去调用父类的某个构造器,则显式的调用一下:super()

(5)super在使用时,需要放在构造器的第一行(因为是先调用父类的构造在再调用子类的构造器)

(6)super和this都只能放在构造器的第一行。因次这两个方法不能同时存在在同一个构造器内 

(7)java所有类都是object类的子类(通过快捷键ctrl+H(IEDA))

(8)父类构造器的调用不限于直接父类,将一直往上追溯直到Object(顶级父类)

(9)子类最多只能继承一个父类,即java中是单继承机制,即(A->B,A->C(->代表继承))是不可实现的。

(10)不能滥用继承,子类和父类必须满足is -a的逻辑关系

五、super关键字

5.1super关键字的基础概念

super代表父类的引用,用于访问父类的属性、方法、构造器。

(1)访问父亲的属性,但不能访问父亲的private属性

(2)访问父亲的方法,但不能访问父亲的private方法

(3)访问父亲的构造器

5.2super关键字的基础代码

父类:

package com.super_;

public class A {
    public int n1 = 100;
    protected int n2 = 200;
    int n3 = 300;
    private int n4 = 400;
    public A(){}
    public A(String name){}
    public A(String name,int age){}
    public void test100(){

    }
    public void test200(){

    }
    void test300(){

    }
    private void test400(){

    }
}

子类:

package com.super_;

public class B extends A{
    //访问父类的属性,但不能访问父类的private属性
    public void hi(){
        System.out.println(super.n1+" "+super.n2+" "+super.n3);
    }
    //访问父类的方法,但不能访问父类的private方法
    public void ok(){
        super.test100();
        super.test200();
        super.test300();
        //super.test400();不能访问父类私有的方法
    }
    //访问父类的构造器:super(参数列表);只能放在构造器的第一句,只能出现一句!
    public B(){
        super();
        //super("jack");
        //super("jack",10);
    }
}

5.3super关键字的相关细节

1.调用父类构造器的好处(分工明确,父类属性由父类初始化,子类的属性由子类初始化)

2.当子类中有和父类中的成员(属性和方法)重名时,为了访问父亲的成员,必须通过super。如果没有重名,使用super、this、直接访问时一样的效果。

3.super的访问不限于直接父类,如果爷爷类和本类中有同名的成员,也可以使用super去访问爷爷类的成员;如果多个基类(上级类)中有同名成员,使用super访问遵循就近原则。

  • 23
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值