一、面向对象的特性之一:继承性
1、为什么使用继承
①提高代码的复用性
②利于维护
③有了继承让类与类之间产生了关系,创建更加特殊的类型(多态)
2、如何使用继承
关键字:extends ---- “扩展”明确子类是父类的扩展
class A extends B{
}
子类:A 父类(超类、基类、SuperClass):B
3、继承的特点
通过继承,子类可以继承父类中所有的属性和方法
私有属性子类也可以继承,只不过因为 private 修饰符的作用,子类不能直接访问
若需要访问则通过公共的 get/set 方法
4、继承的注意
①不能为了简化代码获取某功能而继承,若要继承两个类之间需要满足一定的所属关系:
class A{
void test1(){}
void test2(){}
}
class B extends A{
//void test1(){}
//void test2(){}
}
②Java 只支持单继承,不支持多继承(一个父类可以有多个子类,但是一个子类只能有一个父类)
class A{
void test1(){
//1111111111
}
}
class B{
void test1(){
//2222222222
}
}
class C extends A, B{}
C c = new C();
c.test1();
③Java 支持多层继承
二、方法的重写(方法的覆盖 Override)
若父类中的方法对于子类来说不适用,子类可以对父类方法进行重写
前提:子类继承父类
①方法名和参数列表必须相同
②子类重写方法的访问控制修饰符不能小于父类被重写方法的访问控制修饰符
③子类重写方法的返回值类型可以是父类被重写方法返回值类型的子类
④子类重写方法抛出的异常类型范围不能大于父类被重写方法异常类型的范围
(通常使用时,使方法签名一模一样)
三、super 关键字
使用在子类中,代表父类对象的引用。 super 与 this 使用方式几乎一模一样
super.属性
super.方法
super(……) :调用父类的构造器
①当子类继承父类后,子类“所有”构造中默认第一行第一句有一个隐式的 super()
super() 作用: 调用父类的无参构造器
super() 目的:子类继承父类后,继承父类中所有的属性和方法,因此子类需要知道父类如何为对象进行初始化。(创建子类对象前,需要保证先初始化父类)
②若父类中没有提供无参构造器,子类“所有”构造器中必须显示的调用父类的有参构造器。
③super() 必须使用在构造器中可执行代码的首行
this() 必须使用在构造器中可执行代码的首行
(super() 与 this() 二者不能同时出现)
四、四种访问控制修饰符
public : 公共的,可用于修饰 属性、方法、类。 在任何地方都可以访问
protected : 受保护的,可用于修饰 属性、方法。 可以在本类中、本包中、子类中
default : 默认的(缺省的),可用于修饰 属性、方法、类。 可以在本类中、本包中。
(default 并不是访问控制修饰符的关键字,什么都不加的情况下就是 default)
private : 私有的,可用于修饰 属性、方法。 只能在本类中访问
五、面向对象的特性之一:多态
一类事物的多种表现形态。 人 - 男人 女人
1、多态的体现
①方法的重载与重写 ②对象的多态性
2、对象的多态性
父类的引用指向子类的对象
3、虚拟方法调用(动态绑定)
Java 程序的运行分为两种状态:
在多态的情况下,编译时:“看左边”,看的是父类的引用。(父类中不具备子类特有的方法)
运行时:“看右边”,看的是子类的对象。(实际运行的是子类重写父类的方法)
————虚拟方法调用(动态绑定)
4、引用数据类型之间的转换
前提:要有继承
向上转型:子类转父类。 系统自动完成。
向下转型:父类转子类。 需要使用强转符“(需要转换的类型)”
————ClassCastException
public class PolymorphismTest{
public static void main(String[] args){
/*Man man = new Man();//本态
man.eat();
man.walk();
man.smoking();*/
Person1 p = new Man(); //多态-向上转型
p.eat();
p.walk();
//p.smoking(); 编译?NO
Man man = (Man)p; //向下转型
man.smoking();
//Woman woman = (Woman)p;//编译?YES 运行?NO
}
}
class Person1{
private String name;
private int age;
public Person1() {
}
public Person1(String name, int age) {
this.name = name;
this.age = 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 void eat(){
System.out.println("吃饭");
}
public void walk(){
System.out.println("走路");
}
}
class Man extends Person1{
boolean mustache; //是否有胡子
public void eat(){
System.out.println("男人吃饭狼吞虎咽");
}
public void walk(){
System.out.println("男人走正步");
}
public void smoking(){
System.out.println("男人爱抽烟");
}
}
class Woman extends Person1{
boolean beauty;
public void eat(){
System.out.println("女人吃饭细嚼慢咽");
}
public void walk(){
System.out.println("女人走猫步");
}
public void shopping(){
System.out.println("女人爱购物");
}
}
5、instanceof 运算符
格式:对象的引用 instanceof 引用数据类型
例如:
p instanceof Man : 判断 p 引用指向的对象是不是 Man 的本类类型及子类类型
if(p instanceof Man){
Man man = (Man)p;
man.smoking();
}
6、多态的应用
多态数组
可以存储 Person 本类类型的对象及Person 子类类型的对象
Person1[] persons = new Person1[3];
persons[0] = new Person1("张三", 18);
persons[1] = new Man();
persons[2] = new Woman();
for(int i = 0; i < persons.length; i++){
Person1 p = persons[i]; //多态
p.eat(); //虚拟方法调用
p.walk();
}
多态参数
//需求:展示一个男人吃饭和走路的功能
/*public static void show(Man man){
man.eat();
man.walk();
}
//需求:展示一个女人吃饭和走路的功能
public static void show(Woman woman){
woman.eat();
woman.walk();
}*/
public static void show(Person1 p){//多态参数
p.eat();//虚拟方法调用
p.walk();
if(p instanceof Man){
Man man = (Man)p;
man.smoking();
}
}
六、java.lang.Object 类
是所有类的父类。若一个类没有显示的继承任何类时,默认 extends java.lang.Object
java.lang 是默认包
既然 Object 类是所有类的父类,因此 Object 类中的内容是最具共性的,所有类都适用
既然 Object 类是所有类的父类,因此子类可以继承父类中所有的方法
既然 Object 类是所有类的父类,若 Object 类中的方法对于子类来说不适用,子类可以对其进行重写
1、public boolean equals(Object obj)
比较两个对象是否相等
①在 java.lang.Object 类中
②只能比较两个引用数据类型
③Object 类中的 equals() 比较两个对象的地址值是否相等。(通过查看源码发现实际使用 == 完成的)
④若 Object 类中的方法对于我们来说不适用,我们可以对其进行重写
“==” 运算符:
①基本数据类型:比较两个基本数据类型的值是否相等
②引用数据类型:比较两个引用数据类型的地址值是否相等
2、public String toString()
返回对象的字符串表现形式
①在 java.lang.Object 类中
②直接输出对象的引用默认调用 toString()
③Object 类中的 toString() 返回值的格式为:
getClass().getName() + ‘@’ + Integer.toHexString(hashCode())
④若 Object 类中的 toSting() 对于我们来说不适用,我们可以对其进行重写
class Person /*extends java.lang.Object*/{
private String name;
private int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = 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;
}
//重写 Object 类的 equals() 方法
public boolean equals(Object obj){
if(this == obj){
return true;
}
if(obj instanceof Person){
Person p = (Person)obj;
if(this.name.equals(p.name) && this.age == p.age){
return true;
}
}
return false;
}
//重写 Object 类的 toString() 方法
public String toString(){
return "姓名:" + name + " 年龄:" + age;
}
}
七、static 修饰符
代表静态的,可用于修饰 属性、方法、代码块、内部类
1、static 修饰的属性(静态变量或类变量)
①随着类的加载而加载,随着类的消失而消失(生命周期最长)
②static 修饰的属性被该类所有对象所共享
③一旦某个对象修改了该属性值,其他对象的该属性值也会随之改变
④静态变量的存在优先于对象
⑤可以通过 “类名.类变量”的方式使用
2、静态变量和实例变量的区别
①生命周期不同
②内存中的位置不同
3、static 修饰的方法(静态方法或类方法)
①随着类的加载而加载
②静态方法的存在优先于对象
③可以通过 “类名.类方法”的方式调用
④静态方法中不能使用非静态成员,非静态方法中可以使用静态成员
⑤静态方法中不能使用 this 和 super
八、类的成员之一:代码块
(属性、方法、构造器、代码块)
1、非静态代码块(初始化块)
①格式:类中的一对 {}
②每次创建对象时执行
③代码块的执行优先于构造器
④用于为对象进行初始化(通常用于为多个构造器的共性内容进行初始化)
⑤代码块可以有多个,依次向下的顺序执行
2、静态代码块
①格式:static{}
②随着类的加载而加载,并且只加载一次
③静态代码块的执行优先于非静态代码块
④静态代码块中不能使用非静态成员,也不能使用 this 和 super
⑤静态代码块可以有多个,依次向下的顺序执行
3、为属性赋初始值的方式
①默认值(缺省值)
②直接显示赋值
③构造器
④代码块
顺序:① ②④ ③
注意:②④ 顺序执行
九、final 修饰符
代表最终的,可用于修饰变量、方法、类
1、final 修饰的类不能被继承
2、final 修饰的方法不能被重写
3、final 修饰的变量叫常量,一旦被赋值,值不能改变
①常量的命名规范:所有字母都大写,每个单词之间以“_”隔开
②常量没有默认值,使用前必须赋初始值。(直接显示赋值、构造器、代码块)
若选择使用构造器为常量赋值,必须保证所有构造器都为该常量赋初始值