java课程学习第四课:面向对象(中)


本博客适用于新手学习过程中对java面向对象的一些问题的解答。


一、编程题:设计Src和Dis两个类,Src中有一个被封装的属性,类型为int(要求为非负值),每当通过特定方法更改Src对象中的这个属性时,Dis对象都能得到通知,并向Src发消息获得此属性值
import  java.util.Scanner;
class Dis {
    private Src sc;
    public void setSc(Src sc) {
        this.sc = sc;
    }
    public void show(){
        System.out.println("i am dis ,Age was changed,and the new age is "+sc.getAge());
    }
}
class Src {
    private int age;
    private Dis ds;
    
    public Src( int age){
        this.age = age;
    }
    public void setAge(int age) {
        if(age>0) {
            this.age = age;
        }
        else{
            System.out.println("输入的数据有误");
        }
    }
    public void setDs(Dis ds1){
        this.ds = ds1;
    }
    public int getAge()
    {
        return age;
    }
    public void changeAge(int age1){
        age= age1;
        ds.show();
    }
}
public class javaDemo {
    public static void main(String args[]) {
        Scanner sc1 = new Scanner(System.in);//1
        Dis ds = new Dis();//2
        Src sc = new Src(8);//3
        sc.setDs(ds);//4
        ds.setSc(sc);//5
        int newAge = sc1.nextInt();//6
        sc.changeAge(newAge);//7
    }
}

在这里。两个类中的数据成员都有对方的对象引用,并且有对应的set函数,在主函数的4,5,两行,同时也正是这两个方法建立了两个对象之间的联系。每一次调用changeage方法改变Sc的age属性时,都会调用ds的show方法,使得ds得到通知,同时,二者之间的联系,使得ds可以通过调用内部的Src对象成员来获得改变后的值。


二、Java的访问控制修饰符有哪些?各有什么访问权限?

访问控制权限就是 封装,其核心的一点就是: 只对需要的类可见。
在这里插入图片描述
在这里插入图片描述Java的访问控制修饰符有4种:publicprotectedprivate以及默认(即为缺省,无任何修饰符)。具体情况请看上图。

可以对类或者类中的成员(字段和方法)加上访问修饰符。

  • 类可见表示其他类可以用这个类创建实例对象
  • 成员可见表示其他类可以用这个类的实例对象访问到该成员。

protected用于修饰成员,表示在继承体系中成员对于子类可见,但是这个访问修饰符对于类没有意义。

字段是绝对不能是公有的,如果这样做了,客户端可以对其随意修改,那么就失去了这个字段修改行为的控制。可以用公有的gettersetter方法来替换公有字段,这样的话就可以控制对字段的修改行为。

但是也有例外,如果是包级私有的类或者私有的嵌套类,那么直接暴露成员不会有特别大的影响。

public class AccessWithInnerClassExample {
    
    private class InnerClass{
        int x;
    }
    private  InnerClass innerClass;
    
    public  AccessWithInnerClassExample(){
        innerClass=new InnerClass();
    }
    public int getValue(){
        
        //直接访问
        return innerClass.x;
    }   
}

代码如下(示例):
类前修饰符为public

public class Palne {
    public String name;
    protected int age;
    private int id;

    public Palne(String name,int age,int id){
        this.name = name;
        this.id = id;
        this.age =age;
    }

    public int getId() {
        return id;
    }
    public int setId(){
        return id;
    }
    protected void show1(){
        System.out.println("It's age is"+age);
    }
    private void show2(){
        System.out.println("It's id is"+id);
    }
}

public class test1 {
    public static void main(String args[]){
        Palne pa = new Palne("苏35",18,4);
        System.out.println(pa.name);
        System.out.println(pa.age);
        System.out.println(pa.id);
        pa.getId();
        pa.show1();
        pa.show2();
    }
}

报错如图所示:
在这里插入图片描述修改后,结果如下:

35
18
It's age is18

当我们把类前修饰符换为缺省,在将测试类javaDemo放入另一个包中,效果如下图:在这里插入图片描述此时,Plane类只能由包中的类进行访问,包外的类没有访问权限。


三:子类对于从父类继承的哪些属性与方法是可见的?

子类继承了父类的所有属性和方法, 但只有public、protected的属性和方法在子类是可见的。

子类在继承父类的时候,首先应该满足父类可被访问,例如当子类和父类不在同一个包当中时,父类修饰符必为public;
在父类能被访问的前提下,凡是修饰符为public或是protected的父类属性成员或是方法能被子类所访问;private的属性成员或是方法则不能被访问。

代码如下(示例):

class Plane{
    protected String name;
    public int id;
    private int age;
    public Plane(String name,int id,int age){
        this.name = name;
        this.id = id;
        setAge(age);
    }
    public void setAge(int age) {
        this.age = age;
    }
    public int getAge() {
        return age;
    }
}
class FighterPalne extends Plane{
    private int missileNum;
    public void setMissileNum(int num){
        this.missileNum = num;
    }
    public FighterPalne(String name,int id,int age,int missileNum){
        super(name,id,age);
       setMissileNum(missileNum);
    }
    public int getMissileNum() {
        return missileNum;
    }
    public void show(){
        System.out.println("飞机信息:"+this.name+" 编号:"+this.id+" 服役年龄: "+this.getAge());
        System.out.println("携带弹药数量: "+this.getMissileNum());
    }
}
public class javaDemo{
    public static void main(String args[]){
        FighterPalne pa =new FighterPalne("苏35",6087,4,6);
        pa.show();
    }
}

结果如下:
飞机信息:苏35 编号:6087 服役年龄: 4
携带弹药数量: 6

子类直接调用父类的private属性会报错,即不可见。但是我们可以通过set(),get()。两个公有方法来实现子类对父类private数据的调用。
在这里插入图片描述


四: 什么是组合?有什么作用?

组合就是把一个类当成另一个类的组合成分,从而允许新类直接复用该类的public方法。组合是一种 has-a 的关系,可以理解为有一个。
作用:不破坏封装,整体类与局部类之间松耦合,彼此相对独立且具有更好的可扩展性。
本题的实例代码请看题一。


五: 什么是重载?有什么作用?

存在于同一个类中,指一个方法与已经存在的方法名称上相同,但是参数类型、个数、顺序至少有一个不同。

代码如下(示例):

public class javaDemo {
    public static void main(String args[]){
        int resultA = sum(10,20);
        System.out.println("结果:"+resultA);
        int resultB = sum(10,20,30);
        System.out.println("结果:"+resultB);
        int resultC = sum(10.0,20.0);
        System.out.println("结果:"+resultC);
    }
    public static int sum(int a,int b){
        return a+b;
    }
    public static int sum(int a,int b,int c){
        return a+b+c;
    }
    public static int sum(double a,double b){
        return (int)(a+b);
    }
}

本程序中在主类中一共定义了3个sum()方法,但是这三个方法的参数个数,以及数量完全不相同,那么证明了sum()方法已经被重载了,而在调用方法时,虽然方法的调用名称相同,但是会根据其声明的参数个数或类型执行不同的方法体。

重载的注意事项:
  1. 返回值不同,其他都相同不算是重载。
  2. 代码编写过程中,重载的多个方法往往存在一定的调用关系,即一个方法写有实现功能,其他方法采用委托方式进行调用。
    代码如下(示例):
class Person{
    private String name;
    private int age;

    public Person(){
        System.out.println("*** 一个新的Person类对象实例化了 ***");
    }
    public Person(String name){
        this();
        this.name = name;
    }
    public Person(String name,int age){
        this(name);
        this.age =age;
    }
    public void tell(){
        System.out.println("姓名:"+this.name+", 年龄: "+this.age);
    }
}

public class javaDemo{
    public static void main(String args[]){
        Person per = new Person("张三",12);
        per.tell();
    }
}

本程序利用this()实现了本类其他构造方法的调用,但是此语句使用时必须放在构造方法首行。


六: 什么是覆盖?有什么作用?

覆盖也叫重写,覆写。

存在于继承体系中,指子类实现了一个与父类在方法声明上完全相同的一个方法。

重写有以下3个限制:

  1. 子类方法的访问权限必须大于等于父类方法
  2. 子类方法的返回类型必须是父类方法返回类型或者为其子类型
  3. 子类方法抛出的异常类型必须是父类抛出异常类型或者为其值类型。
    可以使用@Override注解,让编译器帮忙检查是否满足上面的三个限制条件。

示例如下:

public class SuperClass {
    protected List<Integer>func()throws Throwable{
        return new ArrayList<>();
    }
}

public class SubClass extends SuperClass{

    @Override
    public ArrayList<Integer>func()throws Exception{
        return new ArrayList<>();
    }
}

以上的示例中,SubClassSuperClass的子类,SubClass重写了SuperClassfunc()方法。其中:

  • 子类的访问权限为public,大于父类的protected
  • 子类的返回类型为ArrayList<Integer>,是父类返回类型List<Integer>的子类
  • 子类抛出的异常类型为 Exception,是父类抛出异常 Throwable 的子类
  • 子类重写方法使用 @Override 注解,从而让编译器自动检查是否满足限制条件
方法调用的优先级

在调用⼀个方法时,
先从本类中查找看是否有对应的方法,
如果没有再到父类中查看,看是否从父类继承来。
否则就要对参数进行转型,转成父类之后看是否有对应的方法。
总的来说,方法调用的优先级为:

  1. this.func(this)
  2. super.func(this)
  3. this.func(super)
  4. super.func(super)
class A {
    public void show(A obj){
        System.out.println("A.show(A)");
    }
    public  void show(C obj){
        System.out.println("A.show(C)");
    }

    public static void main(String[] args) {
        A a=new A();
        B b=new B();
        C c=new C();
        D d=new D();
		
		//在A中存在show(A obj),直接调用
        a.show(a);//A.show(A)
        
        //在A中不存在show(B obj),将 B 转型成其父类 A
        a.show(b);//A.show(A)
        
        //在 B中存在从A 继承来的show(C obj),直接调用
        b.show(c);//A.show(C)
        
        // 在 B 中不存在 show(D obj),但是存在从 A 继承来的 show(C obj),将 D 转型成其⽗类 C
        b.show(d);//A.show(c)

// 引⽤的还是 B 对象,所以 ba 和 b 的调⽤结果⼀样
        A ba=new B();
        ba.show(c);// A.show(C)
        ba.show(d);// A.show(C)
    }
}
class B extends A{
    @Override
    public void show(A obj){
        System.out.println("B.show(A)");
    }
}
class C extends B{

}

class D extends C{

}



覆盖的注意事项:
  1. 子类方法覆盖父类方法,子类的访问修饰符权限应等于或者大于父类。确保可以使用父类实例的地方都可以使用子类实例去代替。
  2. 同名的static方法和非static方法不能相互覆盖。
  3. 方法前有final修饰符,此方法不能在子类方法中进行覆盖
  4. 在JDK中,很多父类的方法被子类重新覆盖,赋予了不同的含义,如Object类中的boolean equals(Object obj)方法
  5. 抽象类中如果存在抽象方法,则具体子类必须对抽象方法进行覆盖

七、super关键字
  • 访问父类的构造函数:可以使用super()函数访问父类的构造函数,从而委托父类完成一些初始化的工作,注意,子类一定会调用父类的构造函数来完成初始化工作,一般是调用父类的默认构造函数,如果子类需要调用父类其他构造函数,就可以使用super()函数。
  • 访问父类的成员:如果子类重写了父类的某个方法,可以通过使用super关键字来引用父类的方法实现。
public class SuperExample {
    protected  int x;
    protected  int y;

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

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

public class SuperExtendExample extends SuperExample{

    private int z;

    public SuperExtendExample(int x,int y,int z){
        super(x,y);
        this.z=z;
    }

    @Override
    public void func(){
        super.func();
        System.out.println("SuperExtendExample.func()");
    }

    public static void main(String[] args) {
        SuperExample e=new SuperExtendExample(1,2,3);
        e.func();
    }
}

结果如下:

SuperExample.func()
SuperExtendExample.func()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值