永不退缩
I,can do重新出发000008-阅读文章“八_面向对象”
首先我们定义一组对象,分别为:Animal(动物),Primat(灵长类动物),Money(猴子),Person(人类)
而他们的关系是:
那么分别看代码:
Aminal:
package review.base.Java那些事儿.c8_oob;
/**
* 第八节,面向对象的相关内容存放在这里。
*
* 动物类,动物类是相当抽象的对象,并没有具体的属性,所以可以是一个接口,也相对比较合理。
*/
public interface Animal {
/**
* 所有的动物都有eat(吃饭)的行为,但是不同的动物吃的行为是不一样的,所以无法具体的表述。
* 所以eat这个方法在Animal接口中是无法具体实现的。
*/
void eat();
}
Primat:
package review.base.Java那些事儿.c8_oob;
/**
* 灵长类动物继承了动物接口,所以也自动继承了动物eat(吃)的行为(继承的好处之一,不用重复写一次吃这个行为的代码)
*/
public interface Primat extends Animal {
/**
* 灵长类动物是可以行走的,所以此扩展了一个move(行走)的方法
*/
void move();
}
Monkey:
package review.base.Java那些事儿.c8_oob;
/**
* 声明了一个猴子类,同Person相同的继承了Primat(灵长类),但是和Person又具有不同的属性。
*/
public class Monkey implements Primat {
String name;
public Monkey(String name) {
this.name = name;
}
/**
* 同Person一样,需要实现接口的move方法,但是可以提供不同的实现内容。
*/
@Override
public void move() {
System.out.println(name+"吃起了香蕉");
}
@Override
public void eat() {
System.out.println(name+"在树上跳来跳去");
}
}
Person:
package review.base.Java那些事儿.c8_oob;
import java.util.Objects;
/**
* 人类这一层有了具体的属性(年龄和名字),再抽象称接口就不合理了,所以声明成了类
*/
public class Person implements Primat {
String name;
String gender;
private Integer age;
/**
* 构造函数 * @param name 姓名
* @param gender 性别
* @param age 年龄
*/
public Person(String name, String gender, Integer age) {
this.name = name;
this.gender = gender;
this.age = age;
}
@Override
public void move() {
System.out.println(name+"拿起碗和筷子吃饭");
}
@Override
public void eat() {
System.out.println(name+"站起来走路");
}
/**
* 由于年龄这个属性加入了private,外界无法获得,但我们可以提供一个public方法然外部可以访问。
* 这个方法内部进行了处理,不然外界看到女士的年龄。
*/
public void sayAge(){
if(isLady(gender)){
System.out.println(name+"女士年龄保密");
}else{
System.out.println(name+age+"岁了");
}
}
/**
* 判断性别是否为女性。由于采用了private,外部看不到,无法调用该方法,这就是封装。
* @param gender
* @return
*/
private boolean isLady(String gender) {
if("女".equals(gender)){
return true;
}
return false;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Person)) return false;
Person person = (Person) o;
return Objects.equals(name, person.name) &&
Objects.equals(gender, person.gender) &&
Objects.equals(age, person.age);
}
@Override
public int hashCode() {
return Objects.hash(name, gender, age);
}
}
正文开始:
package review.base.Java那些事儿;
import review.base.Java那些事儿.c8_oob.Animal;
import review.base.Java那些事儿.c8_oob.Monkey;
import review.base.Java那些事儿.c8_oob.Person;
import review.base.Java那些事儿.c8_oob.Primat;
public class 八_面向对象 {
public static void main(String[] args) {
System.out.println("a:面向对象是什么?\nb:面向对象就是封装、继承、多态 \na:然后呢?多态是什么?\nb:今天天气不错啊!");
System.out.println();
System.out.println("------正文开始-----------");
Animal animal1 = new Monkey("monkey1");
Animal animal2 = new Person("Eric", "男", 26);
Primat primat = new Person("John", "男", 27);
Person person1 = new Person("Yarn", "男", 26);
Person person2 = new Person("Dan", "女", 27);
System.out.println("\nanimal:");
animal1.eat(); // 以Animal的形态出现,只能调用Animal里的eat方法,虽然Animal的eat没有实现,但是也能打印出我们期望的结果。
animal2.eat();
// animal1.move(); // 编译无法通过,以Animal形态出现,只能调用Animal里的方法。
((Monkey) animal1).move(); // 如果一定要调用,就需要强转。相当于明确告知这个Animal就是一个Money。
// ((Person) animal1).move(); // 但是如果animal1的类型不是Monkey时。就会引发新的问题。java.lang.ClassCastException
System.out.println("\nprimat:");
primat.eat(); // 以Primat形态出现,由于Primat继承了Animal,所以eat()和move()都可以调用。同理,Person的sayAge是无法使用的。
primat.move();
System.out.println("\nperson");
// 以Person形态出现,既可以使用继承的方法,也可以使用自身的方法。
person1.eat();
person1.move();
person1.sayAge();
person2.sayAge();
/**
* 参考文章地址:https://zhuanlan.zhihu.com/p/27681007
*
* 在代码中,不管是动物,鸟类,人类,猴子,我们都可以抽象成类,类是对象的模板,通过new关键字,
* 可以创建一个个对象。仔细看蓝色框里的内容,animal1和animal2,虽然都是同一个形态(Animal),
* 由于指向的是子类对象,当调用同一个eat()方法,运行时会智能匹配到子类的实现,最后得到的结果也不一样,
* 这种形为,我们称之为多态。
*
* 多态满足的三个条件:
* 1、要有继承。
* 2、要有重写。
* 3、父类引用指向子类对象。
*
* ------
* 由于Person中age是private的,isLady()方法。是因为我们在该属性和方法前面加了private关键字。
* 隐藏了不想对客户端暴露的age属性和isLady()方法。
* 对于这种隐藏对象属性和实现细节,仅对外公开指定方法来控制程序中属性的访问和修改,
* 我们称之为封装。(这儿我们没有对age提供set方法,压根没法修改,提供了一个printAge()方法供外部访问)。
*/
}
}