一、面向对象的特性之二:继承
1、为什么使用继承
①提高代码的复用性
②利于维护
③有了继承让类与类之间产生联系,我们可以创建更加特殊的类型(多态)
2、如何使用继承
关键字:extends
eg:class A extends B{}
A 是子类; B 是父类(也叫超类、基类、Superclass)
3、子类继承父类中所有属性(包括私有的)和方法
注意:父类中私有属性,也可以继承,只不过因为 private 修饰符的作用,子类不能直接调用,
若要访问需要通过公共的 set/get 方法
4、继承的注意
①不能为了简化代码,获取某功能而继承,若要继承两个类之间要满足一定的所属关系:is a
②java 只支持单继承,不支持多继承。(一个父类可以有多个子类,但是一个子类只能有一个父类)
③java 支持多层继承
class A{
void test 1(){}
void test 2(){}
}
class B extends A{
// void test 1(){}
// void test 2(){}
}
//错误的使用
/*
class A{
void test1(){
//111111
}
}
class B{
void test1(){
//222222222
}
}
class c extend A,B{}
C c = new C();
c.test1();
*/
二、方法的重写(方法的覆盖Override)
**若父类中的方法对于子类来说不适用,子类可以对父类中的方法进行重写
①方法名和参数列表必须相同 (包括参数的个数、参数的类型)
②子类重写方法的访问控制修饰符不能小于父类被重写方法的访问控制修饰符
(public > protected > default > private)
③子类重写方法的返回值类型是父类被重写方法返回值类型的子类
(通常应用时,使方法签名一模一样)
【面试题】Override 和 Overload 的区别?
方法重载(Overload)
前提:在同一个类中
①方法名必须相同
②参数列表必须不同(参数的个数,参数的类型)
注意:与返回值类型无关
三、super关键字
super 使用方式与 this 几乎一模一样
this :使用在本类中,代表当前对象的引用
super :使用在子类中,代表父类对象的引用
如果构造方法的第一行代码不是 this() 和 super(),则系统会默认添加 super()。
super :属性
super :方法
super(...) : 调用父类构造器
①子类继承父类后,子类 “所有” 构造器中默认第一行第一句有一个隐式的 super()
super() 作用:调用父类的无参构造器
supre() 目的:子类继承父类后,继承了父类中所有的属性和方法,因此子类需要知道父类是怎么为对象进行初始化的
②若父类中没有提供无参构造器,子类 所有 的构造器必须显示调用父类中的有参构造器
(保证在创建子类对象前先初始化父类)
③super() 和 this() 必须使用在当前构造器中可执行代码的首行
因此,super() 和 this() 二者不能同时出现
- super.父类属性名:调用父类中的属性
- super.父类方法名:调用父类中的方法
- super():调用父类的无参构造方法
- super(参数):调用父类的有参构造方法
- this.属性名:表示当前对象的属性
- this.方法名(参数):表示调用当前对象的方法当局部变量和成员变量发生冲突时,使用
this.
进行区分。
关于 Java super 和 this 关键字的异同,可简单总结为以下几条。
- 子类和父类中变量或方法名称相同时,用 super 关键字来访问。可以理解为 super 是指向自己父类对象的一个指针。在子类中调用父类的构造方法。
- this 是自身的一个对象,代表对象本身,可以理解为 this 是指向对象本身的一个指针。在同一个类中调用其它方法。
- this 和 super 不能同时出现在一个构造方法里面,因为 this 必然会调用其它的构造方法,其它的构造方法中肯定会有 super 语句的存在,所以在同一个构造方法里面有相同的语句,就失去了语句的意义,编译器也不会通过。
- this( ) 和 super( ) 都指的是对象,所以,均不可以在 static 环境中使用,包括 static 变量、static 方法和 static 语句块。
- 从本质上讲,this 是一个指向对象本身的指针, 然而 super 是一个 Java 关键字。
四、四种访问控制修饰符
private:私有的,可用于修饰属性、方法、,只能在本类中访问
default:默认的(缺省的) ,可用于修饰属性、方法、类。可以在本类中、本包中。
(注意:default 并不是访问控制修饰符修饰符的关键字,在什么都不加的情况下就是 default)
protect:受保护的,可用于修饰属性、方法、。在本类中、本包中、子类中
public:公共的,可用于修饰属性、方法、类。在任何地方都可以访问
五、面向对象的特性之三:多态
一类事物的 多种表现形态。 eg:人分为男人和女人
1、多态的体现
①方法的重载和重写
②对象的多态性
2、对象的多态性
父类的引用指向子类的对象
Person p = new Man();// 多态
p.eat();
p.sleep;
//p.smoking(); 编译不能通过
3、虚拟方法的调用(动态绑定)
在多态的情况下,编译时:”看左边“,看的是父类的引用,(而父类中没有子类特有的方法)
运行时:”看右边“,看的是子类对象,(实际运行的是子类重写父类的方法)
4、引用数据类型之间的转换
向上转型:子类转父类,系统自动完成
向下转型:父类转子类,需要使用强转符 (需要转换的类型)
可能引发 ClassCastException 异常
Person p = new Man();//多态-向上转型
p.eat();
p.sleep();
Man man = (Man)p;//向下转型
man.smoking();
Woman woman = (Woman)p;//编译 YES 运行 NO 发生 ClassCastException
5、instanceof 运算符
eg:
p instanceod Woman; 判断 p 引用指向的对象是不是 Woman 的本类类型及子类类型,若是 就返回 true
if(p instanceof Woman){
Woman woman = (Woman)p;
}
6、多态的应用
①多态数组
Person[] persons = new Person[3];//数组中可以存储 Person 本类类型的对象及子类类型的对象
persons[0] = new Person();
persons[1] = new Man();
persons[2] = new Woman();
for(int i = 0; i < persons.length; i++){
persons[i].eat();//虚拟方法调用
persons[i].sleep();
}
//增强for循环
for(Person p : persons){//多态
p.eat();//虚拟方法调用
p.sleep();
}
②多态参数:
//需求:展示一个男人吃饭和睡觉的功能
/* public void show(Man man){
man.eat();
man.sleep();
}
//需求:展示一个女人吃饭和睡觉的功能
public void show(Woman woman){
woman.eat();
woman.sleep();
}*/
public void show(Person p){//多态参数,可以接受Person本类类型的对象及子类类型的对象
p.eat();//虚拟方法调用你
p.sleep();
}
六、对象的关联
简单地说,就是一个对象中使用了另一个对象
class Teacher{
private String name;
private int age;
private Computer computer;//对象的关联
public String say(){
return name + "," + age + "," + computer
}
}
class Computer{
public String getDetails(){
return "我是一台高配电脑";
}
}
七、java.lang.Object 类
是所有类的父类,若一个类没有显示的继承任何类时,默认 extends java.lang.Object。
1、既然 Object 类是所有类的父类,因此 Object 类中的内容是最具共性的
2、既然 Object 类是所有类的父类,因此子类可以继承 Object 类中所有的方法
3、既然 Object 类是所有类的父类,若 Object 类中的方法对于子类不适用,子类可以重写 Object 类中的方法
1、public boolean equals(Object obj)
①在 java.lang.Object 中
②作用是比较两个引用数据类型是否相等
③Object 类中的 equals() 比较两个对象的地址值是否相等
2、“==” 运算符
①基本数据类型:比较两个基本数据类型的值是否相等,相等返回 true
②引用数据类型:比较两个引用数据类型的地址值是否相等,相等返回 true
【面试题】== 与 equals 的区别
class ObjectTest{
public static void main(String[] args){
Person p1 = new Person("张三",18);
Person p2 = new Person("张三",18);
System.out.println(p1.equals(p2));// 结果为false
}
}
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;
}
//重写 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;
}
}
3、public String toString()
返回当前对象的字符串表现形式
①在 java.lang.Object 类中
②若直接输出对象的引用时,默认调用 toString()
③Object 类中的 toString 返回的格式如下
getClass().getName().+'@' + Integer.toHexString(hashCode)
④若 Object 类中的 toString() 对于我们不适用,我们可以进行重写
八、static修饰符
代表静态的,可用于修饰 属性、方法、代码块、**内部类
1、static 修饰的属性(静态变量或者类变量)
①随着类的加载而加载,随着类的消失而消失(生命周期最长)
②static 修饰的属性被所有该类的队象所共享
③一旦某个对象修改该属性值,其他对象的该属性值也会随之改变
④静态变量的存在优先于对象
⑤可以通过 ” 类名.类变量“ 的方式使用
2、静态变量与实例变量
①内存中的位置不同
②生命周期不同
3、static 修饰的方法(静态方法或者类方法)
①随着类的加载而加载
②静态方法的存在优先于对象
③可以通过 ”类名.类方法“ 的方式使用
④静态方法中不可以使用非静态成员,非静态方法中可以使用静态成员
⑤静态方法中不能使用 this 和 super
九、类的成员之一:代码块
类成员:属性、方法、构造器、代码块
1、非静态代码块
①格式:类中的一对大括号 {}
②每次创建对象时执行
③非静态代码块的执行优先于对象
④用于为对象进行初始化,(通常用于为构造器中的共性内容进行初始化)
⑤非静态代码块可以有多个,依次向下顺序执行
2、静态代码块
①格式:static
②随之类的加载而加载,并且只加载执行一次
③静态代码块的执行优先于非静态代码块
④静态代码块中不能使用非静态成员,不能使用 this 和 super
⑤静态代码块可以有多个,依次向下顺序执行
十、final 修饰符
代表最终的,可用于修饰 变量、方法、类
①final 修饰的类不能被继承
②final 修饰的方法不能被重写
③final 修饰的变量叫常量,一旦赋值,值不能改变
1)常量的命名规范:所有字母都大写,每个单词以 ‘_’ 隔开。如:XXX_YYY_ZZZ
2)**常量没有默认值,在使用前必须赋值(直接显示赋值、代码块、构造器赋值)
若选择构造器赋值,则保证每个构造器中都为常量辅助