Javalearning_4面向对象再补充

面向对象特性一:封装性

先定义一个Person类:

public class Person {
    String name;
    int age;

    public void eat(){
        System.out.println("人要吃饭");
    }

    public void sleep(){
        System.out.println("人要睡觉");
    }
}

再编写Person Test类:

public class PersonTest {
    public static void main(String[] args) {
        Person p1 = new Person();
        p1.name = "Tom";
        p1.age = 21;
        p1.eat();
        p1.sleep();
        System.out.println(p1.name);
        System.out.println(p1.age);
    }
}

用对象P1.XXX的方式调用Person类里的方法或属性

关键字

有四个权限修饰关键字,由大到小分别为: public 、protected 、缺省 (默认)、private

像String name; int age; 前面没有修饰的就为默认权限

一般来说,我们不希望对象直接访问类中的属性,因此都将属性私有化,而通过公共的get 、set 方法提供一个接口来访问修改这些属性

public class Person {
    private String name;
    private int age;

    public void eat(){
        System.out.println("人要吃饭");
    }

    public void sleep(){
        System.out.println("人要睡觉");
    }
}

私有化属性后,测试类中的name和age会报错,因为Person类的name和age对外不暴露,需要提供方法

    public void setAge(int a){   //设置年龄
        age = a;
    }
    
    public int getAge(){     //获取年龄
        return age; 
    }

引出:this关键字: 在set方法中,参数 a 有时候会忘记代表什么含义;起名字要做到见名知义

(如图,会在调用时提示该参数是什么,如果用a b c这些代替会乱)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VV4LKf3Z-1618241751880)(C:\Users\62561\AppData\Roaming\Typora\typora-user-images\image-20210412222448421.png)]

所以不妨把参数a改成age

但这样一来肯定会报错,所以需要在前面的age前加上 this. :表示“当前对象的”含义

再添加 set和get name方法:

public String getName() {
        return name;
    }

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

这样一来,在测试类中虽然不能直接用 对象.属性来设置,但可以通过set和get方法达到同样的效果

public class PersonTest {
    public static void main(String[] args) {
        Person p1 = new Person();
        p1.eat();
        p1.sleep();
        p1.setAge(2);
        System.out.println("年龄为"+p1.getAge()+"岁");
        p1.setName("Tom");
        System.out.println("姓名为"+p1.getName());
    }
}

构造器

//在创建对象时出现的 Person()是什么呢?
Person p1 = new Person();

回到Person 类,如果我们每次创建一个对象后,都要对他的name 和 age 属性进行赋值,这样显得多余

所以我们希望创建的对象有一个默认值,例如每次new Person()后,他的age 就是4

这里就涉及到构造器:系统中会默认提供一个空参构造器,为

public Person(){    //尝试输入预设初始化值
        age = 1;
    }

如果我们在中间输入一些东西,那么每次创建对象后,他的age就都是1

what’s more,我们不想要每次创建完一个对象后都set他的属性,所以在构造方法中可以提前设置了他的初始化值,例如

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

构造了一个有两个参数的构造器,那么在创建对象时,就可以尝试输入以初始化

Person p1 = new Person("Tom",20);
System.out.println("年龄为"+p1.getAge()+"岁");    //年龄为20岁
System.out.println("姓名为"+p1.getName());        //姓名为Tom

面向对象特性二:继承性

在引入继承性前,先了解 继承的概念

class B extends A{    //   称A为B的父类,B是子类
	
}
   

方法的重载:

如果在一个类中,写了两个同名但不同参的方法,那么这两个方法就构成了重载,例如:

public class Animal {
    public void sleep(){
        System.out.println("动物都要睡觉");
    }
    public void sleep(int hour){
        System.out.println("它想睡"+hour+ "个小时");
    }
}

而系统会根据后面的形参来自动使用具体哪个方法

方法的重写:

在他的子类中,写了一个同名同参的一个方法,那么这两个成为 “重写的方法” 和 “被重写的方法”:

public class Cat extends Animal{
    public void sleep(){
        System.out.println("我家的猫喜欢白天睡觉");
    }
}

为什么要引入继承性?

public class Animal {   
     int age;
     double weight;   
    public void sleep(){
        System.out.println("动物都要睡觉");
    }
    public void sleep(int hour){
        System.out.println("它想睡"+hour+ "个小时");
    }
}

如果在类Animal中,定义了的属性和方法是通用的,如果创建一个Dog类,仍要重新copy一次这些属性和方法,代码显得冗余

所以用extends 关键字,继承了父类中所有的属性和方法

//例如,继承了Animal类后,新写入的方法则为 子类特有的方法
public class Dog extends Animal{
	public void eat(){
        System.out.println("狗喜欢吃骨头");
    }
}

在测试类中

public class AnimalTest {
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.sleep(3);		//它想睡3个小时
        dog.sleep();		//动物都要睡觉
        dog.eat();			//狗喜欢吃骨头
    }
}

面向对象特性三:多态性

还是使用上面的例子,补充

public class Animal {
    public void eat(){
        System.out.println("动物都需要吃东西");
    }

    public void sleep(){
        System.out.println("动物都要睡觉");
    }
    
}
public class Cat extends Animal{
    public void sleep(){
        System.out.println("我家的猫喜欢白天睡觉");
    }

    public void eat(){
        System.out.println("猫喜欢吃鱼");
    }
    
    public void shoot(){
        System.out.println("喵喵喵");
    }
}
public class Dog extends Animal{
    public void sleep(){
        System.out.println("我家的狗喜欢晚上睡觉");
    }

    public void eat(){
        System.out.println("狗喜欢吃骨头");
    }
    
    public void watchdoor(){
        System.out.println("狗可以看门");
    }
}

补充了父类(动物)和他的两个子类(猫、狗) 可以看到sleep 和 eat 方法都是共有的,而子类将这两个方法进行了重写

而Cat类和Dog类分别多了一个父类没有的方法,下面进行测试:

public class AnimalTest {
    public static void main(String[] args) {
        Animal animal = new Dog();
        animal.sleep();
        animal.eat();
        //animal.watchdoor();   编译不通过
    }
}

需要注意的是, 虽然new了一个Dog(),但是他仍然是属于Animal类型,所以在调用方法时,需要用Animal类下的方法,

使用子类特有的方法时会报错

而多态性的使用,简化了代码,使得代码有了通用性,也隐隐透露出“接口”这种思想

在不使用多态性时,如果要用dog的sleep 和 eat 方法

public class AnimalTest {
    public static void main(String[] args) {
        Dog d1 = new Dog();
        d1.sleep();
        d1.eat();
    }
}

如果要用cat的sleep 和 eat 方法:

public class AnimalTest {
    public static void main(String[] args) {
        Cat d1 = new Cat();
        d1.sleep();
        d1.eat();
    }
}

而如果使用多态性:

public class AnimalTest {
    public static void main(String[] args) {
        AnimalTest t1 = new AnimalTest();
        t1.test(new Cat());				//只需修改new 后面的类  看成是一个“入口”
    }

    public void test(Animal animal){     //看成是一个“接口”
        animal.eat();		//传进去不同的类型,都有其对应的重写后了的方法,不用修改
        animal.sleep();
    }
}

这样一来,在编写代码量大的程序时,不必自己再找代码,而只需要修改这个“入口”,改好后不需要管

因为其都有对应重写了的方法,大大节约了修改的地方。

你可能感兴趣的:(学习计划,java)