从面向对象开始,就开始需要理解一些难理解的知识点了,不过不要放弃!!!!
重写(补充一些遗漏的知识点)
方法重写的注意事项:
1、父类中私有的方法不能被重写
2、子类重写父类的方法时候,访问权限不能更低,要么子类重写的方法访问权限比父类的访问权限要高或者一样,建议:以后子类重写父类的方法的时候,权限修饰符写一样就不会发生这样的问题。
3、父类中静态的方法不能被重写,也就是说不能被Override修饰,因为静态的是属于类本身的东西。
根据例题进行理解:新手机时旧手机的子类
class OldPhone1{
private String name;
public void call(String name) {
System.out.println("打电话给" + name);
}
public static void play(){
System.out.println("玩俄罗斯方块");
}
}
class NewPhone1 extends OldPhone1{
@Override
public void call(String name){
//在子类重写的方法,想要调用父类中的方法,运用关键字super.成员
super.call(name);
System.out.println("看抖音");
}
//说明被static关键字修饰的方法不能重写
// @Override
public static void play(){
System.out.println("玩王者荣耀");
}
}
public class ExtendsDome1 {
public static void main(String[] args) {
NewPhone1 n1 = new NewPhone1();
n1.call("XXX");
//这不算重写,这算是在子类的独有方法
//可以根据原先static的知识,用类名直接访问方法
NewPhone1.play();
}
}
再看看下面的运行结果是什么(也就是常说的看程序写结果)
class A1{
//将父类中的静态成员看作一个全局共享的,被所有的子类共享
public static int a = 10;
public static void fun(){
System.out.println("hello");
}
}
class B1 extends A1{
public void fun2(){
a = 200;
System.out.println(a);
}
public static void fun(){
System.out.println("world");
}
}
public class ExtendsDemo2 {
public static void main(String[] args) {
B1 b = new B1();
System.out.println(b.a);//10
b.fun();//world
b.fun2();//200
System.out.println(b.a);//200
System.out.println(A1.a);//200
}
}
final关键字
final的特点:
final:最终的的意思。它可以修饰类,成员变量,成员方法
特点:
1、修饰类,类不能被继承
2、修饰成员变量,变量变常量,并且只能赋值一次,在构造方法完毕之前赋值即可。
常量:
字面值常量
自定义常量:被final修饰变量变成自定义常量
3、final修饰成员方法:方法不能被重写
面试题:
final修饰局部变量
1、在方法内部,修饰基本数据类型的变量,变量值只能赋值一次,不能发生改变
2、final修饰引用数据类型的变量呢?
引用的地址值不可以发生改变你,但是该对象的堆内存中的值是可以发生改变的。
class Fu3 {
int num = 10;
public void show1(){
num = 100;
}
}
class Zi3 extends Fu3 {
public void show() {
System.out.println(num);
}
}
public class FinalDemo2 {
public static void main(String[] args) {
final Fu3 f = new Fu3();
//因为f为final类型的对象,不能在将其他的地址值赋值给f了
//但是里面的成员变量(不是final类型的)还是可以进行改变
// f = new Fu3();
f.show1();
System.out.println(f.num);
//z.show();输出为10,说明在子类创建的时候,得先将父类的成员变量初始化以及构造方法运行一遍
Zi3 z = new Zi3();
z.show();
}
}
引入多态的概念:
多态:某一事物,在不同时刻表现出来的不同状态
举例:
水:
固态、液态、气态
固态的水是水、液态的水也是水、气态的水也是水
水果:
波罗蜜、香蕉、榴莲
波罗蜜是水果、香蕉是水果、榴莲是水果
水果是波罗蜜。// 反过来说是有问题的
动物:
狗、虎、猫、大象
狗是动物,这么说是没问题的
动物是狗,这么说是不可以。
说了这么多,总结出一个思想,这个思想叫做:多态
通过观察例子发现,要想有多态,就必须要继承,继承是多态的前提。
多态的前提:
1、要有继承关系
2、要有方法的重写。
其实没有重写也是可以的,但是不重写就没有意义
动物都有吃这个方法,但是每个具体的动物吃的实现不一样,变现出不同动物的特有属性
3、要有父类的引用指向子类对象
父类名 f = new 子类名(...);
多态访问成员的特点:
1、成员变量
编译看左,运行看左
2、构造方法
创建子类对象的时候,先访问父类中的构造方法,对父类的数据先进行初始化
3、成员方法
编译看左,运行看右。
因为成员方法存在重写,所以访问看右边
4、静态成员方法
编译看左,运行也看左。
由于被static修饰的成员都是与类相关的,这里不是重写,所以运行的时候,访问的还是左边的。
自己的总结:
多态访问成员变量的特点:
父类的引用指向子类对象
父类名称 对象名称 = new 子类名称();
左边 右边
1、成员变量:想要输出f.成员变量时,只会去父类中去找成员变量如果找到就输出,如果没找到,则输出错误
2、构造方法:在创建的时候,先创建父类的构造方法,再构造子类的方法
3、成员方法:f.方法名 运行时,编译看左边,运行看右边,意思是:运行方法之前先会去父类的方法中去寻找
show方法,如果没找到直接报出错误,如果找到的话,则是运行子类的show方法,也想要运行父类的时,加上super.show();
4、静态的成员方法:static不支持重写,只是单纯的调用父类的静态方法,因为static时类特有的属性,随着类的加载而加载
根据代码进行理解
class Fu4 {
int num = 100;
Fu4() {
System.out.println("这是父类的构造方法");
}
//当父类没有这个方法的时候,会报错
// java: 找不到符号
// 符号: 方法 show()
// 位置: 类型为com.shujia.yl.day11.Fu4的变量 f
public void show() {
System.out.println("这是父类的show方法");
}
public static void fun(){
System.out.println("这是父类的fun方法");
}
}
class Zi4 extends Fu4 {
int num = 1000;
Zi4() {
System.out.println("这是子类的构造方法");
}
@Override
public void show() {
super.show();
System.out.println("这是子类的show方法");
}
public static void fun(){
System.out.println("这是子类的fun方法");
}
//想要直接 f.show2()的方法获取方法是不可以的,因为程序再运行之前回去父类中查到是否有一样的方法,这是多态的弊端
//但是可以解决:向下类型转换即可
public void show2() {
System.out.println("这是子类的特有的方法");
}
}
public class PolymorphicDemo1 {
public static void main(String[] args) {
Fu4 f = new Zi4();
//输出父类的成员变量
System.out.println(f.num);
f.show();
//这里static不支持重写,所以这里只是单纯的调用父类的静态方法::::前面说过可以用Fu4.fun();代替
f.fun();
// f.show2();
//向下类型转换
Zi4 z = (Zi4) f;
z.show2();
}
}
尤其记住多态访问成员的特点(很重要很重要很重要)你不记住的话,后面会很晕很晕
多态的前提:(三个缺一不可)
1、要有继承的关系
2、子类要重写父类中的方法
3、父类的引用指向子类对象
多态的弊端:
多态无法使用子类特有的方法
1、我就想使用父类中的方法,能不能用,能。不使用多态
2、如果我想使用子类中的特有方法,还必须使用多态,咋办?
1)就不使用多态,创建子类对象然后调用方法,但是在我上一个例子上,再次创建对象,还会在堆内存中开辟空间,很有可能会造成资源浪费
2)以我们目前的知识,我们还不会,但是我们想一想之前的数据类型。将子类看成一个小的类型,将父类看成一个大的类型,现在想要用小的类型中的方法我们应该要将大的类型转成小的类型。在我们之前的做法是用强制类型转换。 如果在继承关系,也有类似的这样的做法就好了。 java替我们考虑到这样的问题,提供了一个技术给我们使用:
向下转型,将父类的引用强制转换成子类的引用
子类类名 变量名 = (子类类名)父类的引用;
对象之间转型的问题:
1、向上转型:Fu f = new Son();
2、向下转型:Son s = (Son)f;
有点像数据类型的转换,int a = 10;,byte b = (byte)a;
向下转型需要注意的一个问题:
要求转型的类与父类引用存在继承关系,并且一开始创建多态的时候,使用的是该类。
/*
向下转型猫狗案例
*/
class Animal2{
public void eat(){
System.out.println("吃");
}
}
class Dog2 extends Animal2{
@Override
public void eat() {
System.out.println("狗吃肉");
}
public void lookDoor(){
System.out.println("看门");
}
}
class Cat2 extends Animal2{
@Override
public void eat() {
System.out.println("猫吃鱼");
}
public void catchMouse(){
System.out.println("猫捉老鼠");
}
}
关键字abstract(抽象)
怎么理解abstract呢?
抽象的表述:
我们之前所说的猫,狗,猪,熊猫,老虎等等都是动物具体的例子,而动物本身是一个抽象的概念
但是回想一下我们之前都是将动物写成了一个具体的,而类又可以创建对象,但是实际上抽象的东西本身应该不能被实例化
并且动物中吃的方法应该也不是一个具体的实现,以及所有动物共同拥有的方法在动物中应该都是抽象的表现
我们今天之后,我们把一个不具体的功能,叫做抽象方法,而如果一个类中有抽象方法,我们就把这个类称之为抽象类。
抽象类的特点:
1、抽象类和抽象方法都要用一个关键字修饰:abstract
修饰一个类 放在class的前面
举例: abstract class Animal3{}
修饰一个方法 一般是放在权限修饰符后面
定义一个抽象的show方法
举例:public abstract void show();
2、有抽象方法的类一定要是抽象类,抽象类不一定要有抽象方法,具体的类中不能有抽象方法,抽象类中既可以存在抽象方法
也可以存在有方法体的方法。
3、抽象类不能被实例化
既然不能被实例化,那写在抽象类中的方法如何被调用呢?
抽象类如何创建呢?
通过多态的形式,使用具体的子类去实例化调用方法,专业术语称之为:抽象多态
4、如果继承抽象类的是一个具体的子类,需要重写该抽象类中所有的抽象方法
如果继承抽象的也是一个抽象类,可以不去重写父类中的抽象方法,也可以选择性的去重写。
抽象类的成员的特点:
成员变量:
既可以是变量,也可以是常量
构造方法:
可以存在构造方法,我们上一个程序中,才总结出抽象类不能被实例化,这里构造方法意义是什么?
我们之前在继承中还说过要想初始化子类,必须先初始化父类,所以这里构造方法是提供初始化父类的作用
成员方法:
可以是抽象方法,但是具体的子类必须要重写该方法
也可以不是抽象方法,提高代码的复用性。
abstract关键字不能和哪些关键字共存?
private
static
final
学习总结(至此面向对象的三大特征介绍完了,后面还会学习接口的知识,所以我们先来个面向对象的总结1.0—):
面向对象的三大特征:
封装、继承、多态、
一、封装:隐藏类中的属性,提供公共的方法给外界
1、private 私有,它可以修饰成员变量,构造方法,成员方法
一个标准类1.0:
成员变量:被private
成员方法:getXxx()和setXxx()
show(): 遍历所有成员变量值
2、this关键字
一个标准类2.0:
给变量名起名讲究见名之意,为了可以去调用当前对象中的成员变量,我们引出了this
this代表的是调用方法的当前对象
3、构造方法
为了创建对象
1、可以发生重载
2、可以给成员变量进行初始化值
一个标准类的3.0
成员变量:使用private关键字修饰
构造方法:一个无参构造方法/一个带所有参数的构造方法
成员方法:getXxx()/setXxx() …
show(): 遍历所有的成员变量值
4、static
可以被所有类的对象共享的成员,使用static修饰
特点:可以直接通过类名.静态成员的方式调用
随着类的加载而记载的,也称之为类成员
二、继承:多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和行为,只要继承那个类即可。
1、定义语句格式
class A{}
class B extends A{}
B称之为子类,或者派生类
A称之为父类,超类或者基类
2、java中类只支持单个继承,不支持一次继承多个类,但是可以多层继承
3、super关键字,在子类要想访问父类的成员,就是用super关键字
super可以访问父类非私有成员变量,构造方法,成员方法
this也可以访问本类非私有成员变量,构造方法,成员方法
面试题:this与super的区别?
4、要想初始化子类必须先初始化父类。
5、重写:是发生在继承的关系中
子类重写/覆盖父类中的方法,声明与父类中的一模一样,只是实现不一样而已
面试题:重写与重载的区别/overload和override的区别
6、final关键字:它可以修饰成员变量,成员方法,类
修饰类:类不能被继承
修饰成员变量:变量变自定义常量
修饰成员方法:方法不能被重写
7、final修饰变量的初始化时机
在对象构造完毕前即可
8、多态:
多态的前提:
要有继承关系
要有方法的重写
要有父类的引用指向子类的对象
多态访问成员的特点:****
成员变量:编译看左,运行看左
成员方法:编译看左,运行看右
静态成员方法:编译看左,运行也看左**
多态的弊端:不能访问子类特有的方法
解决方案:向下转型
关键字abstract,它可以修饰类,方法
1、抽象类中可以没有抽象方法,但是有抽象方法的类一定是抽象类
2、抽象类不能被实例化
3、要想实例化抽象类,必须用一个具体的子类继承它
注意:具体的子类继承抽象类,必须重写该抽象类中的所有的抽象方法
4、最终以抽象多态的形式进行实例化。