Day09
面对对象
一、继承的使用
理解:子类继承父类所有的属性和方法
注意:
- 类与类之间的关系叫做继承
- 一个类只能继承另外一个类 – 单继承
应用场景:
编写多个类时,发现多个类有相同的属性和方法,
就可以将相同的属性和方法抽取出,放在共同的父类里
继承的优缺点:
优点:减少了代码的冗余
缺点:增加了类关系的复杂度
需求:创建中国人和日本人的类,并且创建对象、操作对象
分析:
人类:
属性:姓名、性别、年龄
方法:吃饭、睡觉
中国人类 继承 人类
属性:身份证
方法:打太极
父类
public class Person {
String name;
char sex;
int age;
private String field = "父类私有化的成员变量";
public String getField() {
return field;
}
public void setField(String field) {
this.field = field;
}
public Person() {
System.out.println("父类的构造方法");
}
public void eat() {
System.out.println(this.name + "吃饭");
}
public void sleep() {
System.out.println(this.name + "睡觉");
}
}
子类
public class Chinese extends Person{
String id;
public Chinese() {
//默认实现:调用父类非私有化的无参构造
//super();
System.out.println("子类的构造方法");
}
public void playTaiJi(){
System.out.println("中国人打太极");
}
}
测试类
public static void main(String[] args) {
//创建中国人对象
Chinese c = new Chinese();
//设置父类成员属性
c.name = "蔡徐坤";
c.sex = '男';
c.age = 23;
//设置子类成员变量
c.id = "123456";
//获取父类成员变量
System.out.println(c.name);
System.out.println(c.sex);
System.out.println(c.age);
//获取子类成员变量
System.out.println(c.id);
//调用父类成员方法
c.eat();
c.sleep();
//调用子类成员方法
c.playTaiJi();
}
继承的深入
创建子类对象时,是否会调用父类构造方法?
会的
创建子类对象时,先调用父类构造方法还是先调用子类构造方法?
先调用子类的构造方法
创建子类对象时,先完成父类构造方法还是先完成子类构造方法?
先完成父类的构造方法
创建子类对象时,会不会创建父类对象?
不会
创建子类对象时,为什么会调用父类的构造方法?
创建子类对象,调用父类方法的目的是在子类对象中开辟空间存储父类的成员属性
子类能否继承父类私有化的属性和方法?
可以,但是不能直接使用,必须间接调用(私有化属性设置对应的公有化的方法,调用公有化的方法去操作私有化的属性)
二、super
理解:super表示父类的
作用:
- super.属性:在子类中,调用父类非私有化的成员变量
- super.方法:在子类中,调用父类非私有化的成员方法
- super():在子类中的构造方法的第一句调用父类非私有化的构造方法
三、重写/复用
理解:将父类的方法在子类中重新写一遍
应用场景:父类方法不满足子类需求时,且父类方法不能被改动,就可以考虑在子类中重写
条件:
- 在子类中重写
- 返回值、方法名、参数列表必须和父类重写的方法一致
- 访问修饰符不能比父类的方法更严格
public class Person {
private String name;
private char sex;
private int age;
public Person() {
}
public Person(String name, char sex, int age) {
this.name = name;
this.sex = sex;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public char getSex() {
return sex;
}
public void setSex(char sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public void eat() {
System.out.println(this.name + "吃饭");
}
public void sleep() {
System.out.println(this.name + "睡觉");
}
}
public class Chinese extends Person{
private String id;
public Chinese() {
}
public Chinese(String id) {
//super(); -- 默认实现:调用父类非私有化的构造方法
this.id = id;
}
public Chinese(String name, char sex, int age, String id) {
super(name, sex, age);
this.id = id;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public void playTaiJi(){
System.out.println(super.getName() + "打太极");
}
//@Override - 重写的注解,描述该方法是重写父类的
@Override
public void eat() {
System.out.println(super.getName() + "吃山珍海味");
}
}
import test03.Chinese;
public class Test01 {
public static void main(String[] args) {
//创建中国人的对象
Chinese c = new Chinese("蔡徐坤", '男', 23, "1234567890");
c.eat();
c.sleep();
c.playTaiJi();
}
}
四、访问修饰符
理解:定义类、接口、属性、方法的访问权限
分类:
- private(私有的)
- default(默认的)
- protected(受保护的)
- public (共有的)
注意:
- 类和接口上只能使用public和默认的访问修饰符
- 属性和方法都可以使用四个访问修饰符修饰
访问修饰符 | 本类中 | 本包中 | 其他包的子类 | 其他包 |
---|---|---|---|---|
private | OK | |||
默认的 | OK | OK | ||
protected | OK | OK | OK | |
public | OK | OK | OK | OK |
经验:
- 属性一般使用private修饰
- 属性要想给子类使用,一般使用protected
- 方法一般使用public修饰
- 方法要想只在该类中使用,一般使用private
- 方法要想给子类使用/重写,一般使用protected
五、Object类
Object了解
理解:Object是所有类的超类/基类,如果一个类没有明确继承的类,该类默认继承Object
equals()
理解:判断两个对象的内存地址是否相同
public static void main(String[] args) { Object obj1 = new Object();//0x001 Object obj2 = new Object();//0x002 System.out.println(obj1 == obj2);//false System.out.println(obj1.equals(obj2));//false /** * Object类 -- equals底层: * public boolean equals(Object obj){ * // obj1 == obj2 * return (this == obj); * } */ }
getClass()
前言:使用到类,JVM会将该类的class文件加载到方法区(1次),并在堆中创建class对象,所以class对象是唯一的
理解:获取到该类的class对象
public static void main(String[] args) { Object obj1 = new Object();//0x001 Object obj2 = new Object();//0x002 Class<? extends Object> class1 = obj1.getClass();//获取Object类的class对象 Class<? extends Object> class2 = obj2.getClass();//获取Object类的class对象 System.out.println(class1 == class2);//true System.out.println(class1.getName());//java.lang.Object System.out.println(class2.getName());//java.lang.Object }
hashCode()
理解:获取对象的hash值(hash值=内存地址+散列算法)
public static void main(String[] args) { Object obj1 = new Object();//0x001 Object obj2 = new Object();//0x002 int hashCode1 = obj1.hashCode(); int hashCode2 = obj2.hashCode(); System.out.println(hashCode1); System.out.println(hashCode2); }
toString()
理解::将对象转换为字符串
public static void main(String[] args) { Object obj = new Object(); //java.lang.Object@15db9742 System.out.println(obj);//打印对象,默认调用toString() System.out.println(obj.toString()); /** * Object类的toString()底层: * * public String toString(){ * * // java.lang.Object @ 15db9742 * return getClass().getName() + "@" + Integer.toHexString(hashCode()); * } */ }
Object类的使用
- equals():判断两个对象是否相同,不同的子类有着不同的判断规则,子类重写即可
- getClass():先不管,在反射的技术点中学习
- hashCode():先不管,在集合的技术点中学习
- toString():将对象转换成字符串,不同的子类有着不同的属性,子类重写即可
编写类的步骤:
- 属性
- 私有化属性
- 无参构造
- 有参构造
- get/set方法
- 独有的方法
- 重写equals
- 重写toString
public class User {
private String username;
private String password;
private String nickName;
public User() {
}
public User(String username, String password, String nickName) {
this.username = username;
this.password = password;
this.nickName = nickName;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getNickName() {
return nickName;
}
public void setNickName(String nickName) {
this.nickName = nickName;
}
//obj - 0x002
@Override
public boolean equals(Object obj) {
//先判断两个对象内存地址是否相同
//user1 == user2
//0x001 == 0x002
if(this == obj){
return true;
}
//user - 0x002
User user = (User) obj;
//0x001.username.equals(0x002.username)
if(this.username.equals(user.username)){
return true;
}
return false;
}
@Override
public String toString() {
return username + " -- " + password + " -- " + nickName;
}
}
public class Test01 {
public static void main(String[] args) {
User user1 = new User("147258369", "123123", "蔡徐坤");//0x001
User user2 = new User("147258369", "123123", "蔡徐坤");//0x002
System.out.println(user1.equals(user2));//true
System.out.println(user1);
System.out.println(user2);
}
}
Object的使用 – 深入String底层原理
public class MyString {
private final char[] value;
public MyString(String original) {
//toCharArray() -- 将字符串转换为字符数组
value = original.toCharArray();
}
@Override
public boolean equals(Object obj) {
if(this == obj){
return true;
}
MyString my = (MyString) obj;
char[] v1 = this.value;//my1.value -- ['a','b','c']
char[] v2 = my.value;//my2.value -- ['a','b','c']
int length = v1.length;
if(length == v2.length){
for (int i = 0; i < length; i++) {
if(v1[i] != v2[i]){
return false;
}
}
return true;
}
return false;
}
@Override
public String toString() {
String str = "";
for (char element : value) {
str += element;
}
return str;
}
}
public class Test01 {
public static void main(String[] args) {
String str1 = new String("abc");
String str2 = new String("abc");
System.out.println(str1 == str2);//false
System.out.println(str1.equals(str2));//true
System.out.println(str1);//abc
System.out.println(str2);//abc
System.out.println("---------------------------------");
MyString my1 = new MyString("abc");
MyString my2 = new MyString("abc");
System.out.println(my1 == my2);//false
System.out.println(my1.equals(my2));//true
System.out.println(my1);//abc
System.out.println(my2);//abc
}
}
总结
- 继承的使用
- 继承的深入
- super
- 重写
- 访问修饰符 – 做实验
- Object(了解、使用、MyString)