1.面向对象
1.1 this关键字
- this定义: 当代码中局部变量和成员变量同名时, 此时调用方法中的变量根据就近原则.
- 解决: 为了避免局部变量和成员变量同名时, 产生的歧义性, 我们使用this关键字去直接访问成员变量.
- 使用构造器和使用setter方法区别
构造器: 在创建对象的时候设置初始数据, 只能初始化一次.
setter方法: 创建对象后再设置初始数据可以设置多次.
1.2 继承
1.2.1 继承的概念
- 继承定义: 如果一个类需要继承另一个类, 此时使用extends关键字
- 继承语法
public class 子类名 extends 父类名{
}
- 继承概念: 被继承的类, 叫父类或者基类.
继承父类的类, 叫子类或者拓展类.
父类: 存放多个子类公共的字段和方法.
子类: 存放自己特有的字段和方法.
- 注意: Java中的类只支持单继承, 但是支持多重继承(不是多继承).
一个父类可以有多个子类.
- Object 类是Java语言的根类, 任何类都是Object的子类, 要么是直接子类, 要么是间接子类.
1.2.2 判断子类可以继承什么
子类继承父类之后, 可以拥有到父类的某一些成员( 字段和方法 ), 根据访问修饰符来判断:
-
如果父类中的成员使用public和protected修饰, 子类都能继承.
-
如果父类和子类在同一个包中, 使用缺省访问修饰的成员, 此时子类可以继承到.
-
如果父类中的成员使用private修饰, 子类继承不到. private只能在本类中访问.
-
父类的构造器, 子类也不能继承, 因为构造器必须和当前的类名相同.
1.3 方法覆盖
当子类存在一个和父类一摸一样的方法的时候, 我们就说子类覆盖了父类的方法, 也叫重写.
//父类鸟
public class Bird {
//鸟会飞的方法
public void fly() {
System.out.println("飞");
}
}
//子类鸵鸟
public class Ostrich extends Bird {
public void fly(){
System.out.println("不会飞");
}
}
//需求:演示方法覆盖
public class OverrideDemo {
/*
父类鸟类(Bird),鸟类中含有飞翔(fly)行为
鸟的子类鸵鸟类(Ostrich),子类中覆盖父类飞翔(fly)方法
*/
public static void main(String[] args){
Ostrich o = new Ostrich();
o.fly();
}
}
- 方法调用的顺序: 在子类先找有没有对应的方法, 没有就执行父类的, 子类有就执行子类的, 都没有就报错.
- 方法覆盖的细节:
private修饰的方法不能被子类继承, 也就没有覆盖.
-
实例方法签名必须相同 (方法签名= 方法名 + 方法的参数列表).
-
子类方法的返回值类型是和父类方法的返回类型相同或者是其子类.
-
子类方法中声明抛出的异常小于或等于父类方法声明抛出异常类型.
-
子类方法的访问权限比父类方法访问权限更大或相等.
总结:以上4点不明白就直接拷贝父类中方法的定义粘贴到子类中,再重新编写子类方法体.
1.4 super关键字
super作用: 当子类的方法覆盖了父类的方法, 我们再想子类去调用父类方法时, 就要使用super.方法名().
//子类鸵鸟
public class Ostrich extends Bird {
public void fly(){
System.out.println("不会飞");
}
public void say(){
fly();
super.fly();
}
}
1.5 抽象方法和抽象类
用抽象修饰的方法具备两个特征:
-
该方法没有方法体.
-
要求子类必须覆盖该方法.
使用abstract修饰的方法,称为抽象方法.
public abstract 返回类型 方法名(参数);
特点:
-
使用abstract修饰,没有方法体,留给子类去覆盖.
-
抽象方法必须定义在抽象类或接口中.
使用abstract修饰的类,成为抽象类.
public abstract class 类名{
}
一般的,抽象类以Abstract作为类名前缀, 一看就能看出是抽象类.
特点:
-
抽象类不能创建对象, 调用没有方法体的抽象方法没有任何意义.
-
抽象类中可以同时拥有抽象方法和普通方法.
-
抽象类要有子类才有意义, 子类必须覆盖父类的抽象方法, 否则子类也得作为抽象类.
//表示求形状面积的抽象类,里面包含求面积的抽象方法,其他子类必须覆盖此方法
public abstract class AbstractGraph {
public abstract double getArea();
}
1.6 Object类和常用方法
Object本身是表示对象的意思, 是Java中的根类, 要么是一个类的直接父类, 要么就是间接父类.
class A{} 其实等价于 class A extends Object{}
因为所有类都是Object类的子类, 所以类的所有对象都可以调用Object类中的方法.
1.6.1 equals方法
在Object类中的equals方法和"==" 符号是相同的都是比较对象是否在同一个存储地址.
实际开发中: 我们通常是比较两个对象中的成员变量的值是否相等, 来判断两个对象是否相同
官方建议:每个类都应该覆盖equals方法去比较我们关心的数据,而不是内存地址。
1.6.2 toString方法
表示把对象中的字段信息转换为字符串格式
默认情况下打印的是对象的hashCode值, 但是我们更关心对象中字段存储的数据.
官方建议: 应该每个类都应该覆盖toString返回我们关心的数据.
public class Person {
protected String name;
protected int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public boolean equals(Object o) {
return true;
}
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
//需求:演示Object类中的toString和equals方法
public class ObjectDemo {
//- 创建一个Person类,通过覆盖toString方法,打印Person对象的内容
//
//- 使用==和equals比较两个Person对象,通过结果得到==和equals的区别
public static void main(String[] args){
Person p = new Person();
p.setName("周");
p.setAge(17);
Person p1 = new Person();
p1.setName("周");
p1.setAge(17);
boolean result1 = p == p1;
boolean result2 = p.equals(p1);
System.out.println(result1);//地址不同false
System.out.println(result2);//值相同true
//官方toString输出:com.day02.demo.objectdemo.Person@2133c8f8
//在Person覆盖官方的toString方法
//Person{name='周', age=17}
System.out.println(p1.toString());
//实际开发中使用,因为println方法会去调用传递参数的toString方法
System.out.println(p1);
}
}
拓展:
== 符号到底比较的是什么:
-
比较基本数据类型: 比较两个值是否相等
-
比较对象数据类型: 比较两个对象是否是同一块内存空间(地址是否相同).
每一次使用new关键字, 都表示在堆中创建一块新的内存空间.
2.总结
2.1 this关键字的作用
当类中的成员变量和形式参数的名字一样时, 为了避免歧义性(就近原则), 我们使用this可以直接指向成员变量.
2.2 为成员变量设置值, 构造器和setter方法的选择
构造器: 构造器可以一边创建对象一边赋值, 但是只能赋值一次.
setter方法: 创建对象后再赋值, 可以设置多次.
2.3 为什么需要继承?
当多个类中的成员变量, 成员方法(存在相同代码),都是一样的时候, 为了简化代码我们可以使用继承.
2.4 Java中的继承语法
语法: public class 子类名 extends 父类名{}
2.5 子类能从父类中继承到哪些成员?
使用public和protected修饰子类都可以继承, 当父类子类在同一个包中, 没有使用修饰符的也可以继承.
2.6 子类什么时候需要覆盖父类中的方法?
当父类的方法不符合子类的信息的时候我们应该使用覆盖.
2.7 super关键字的作用
super: 当子类覆盖了父类的方法时, 我们还想去调用父类的方法就要使用super.方法名.
2.8 什么时候需要把父类中的方法定义成抽象方法?
当父类的方法没有什么实际意义(不需要方法体), 而子类都必须覆盖该方法的时候.
2.9 抽象类应该怎么使用?可以直接使用抽象类创建对象吗?
抽象类: 抽象类的命名应该带有abstract, 让人知名见意, 抽象类必须有抽象方法, 子类必须覆盖父类的抽象方法.
不可以直接使用抽象类创建对象.
2.10 Object中的toString()的作用?实际开发中如何使用?
toString: Object类的toString()方法默认返回该对象实现类的“类名+@+hashcode”值.
实际开发: 在实际开发中我们需要自定义toString(), 让对象中的字段信息转换为我们想要的字符串格式
2.11 Object中的equals()和==的区别?实际开发中如何使用?
相同: 在比较对象时Object中的equals( )和==都是比较地址是否相同
不同: ==可以用来比较基本数据类型的值是否相等, equals( )不行.
实际开发: 我们需要自定义equals( ) 方法, 用equals来比较对象中的值是否相等