Java就业班_面对对象

继承

继承是面对对象三大属性之一 (封装继承多态)
子类继承父类就会获得父类中的方法和属性,不仅如此子类还可以定义父类中没有的方法、比如说重写父类中的方法,会让子类中的功能更加丰富

继承的好处:
1.提高代码复用性(多个类相同的属性和方法可以定义为父类)
2.提高代码维护性(只需要维护父类)

继承的弊端:
增加类的耦合性,当父类变化时子类强制性的都会做出变化

什么时候使用继承?
如果俩个类之间存在包含和被包含关系就可以考虑使用继承

super关键字:
this代表本类对象的引用,super代表父类对象引用

继承中构造方法的访问特点?
子类中所有的构造方法都会先访问父类中的无参构造方法
为什么?
因为子类会继承父类中的数据在此之前需要先完成父类的数据初始化。
每一个子类构造方法第一条语句默认都是:super()
如果父类中没有无参构造方法,可以用super(),调用父类带参构造方法完成父类初始化

继承中成员方法和变量的访问特点?
在子类方法中访问一个变量,先在子类局部范围找,再到子类成员变量
再到父类成员变量中找,如果没有就报错

通过子类对象去访问方法,如果子类中有,则用子类的成员方法,
如果没有则用父类的成员方法,再没有就报错

继承的注意事项:
1.子类不能继父类的私有属性和方法
2.子类不能继承父类的构造方法,不过可以调用父类静态方法,但是不能通过父类的构造方法来实例化子类对象,只能通过父类的构造方法来( super( ))完善子类的构造方法,且子类中的构造方法第一句一定是super调用父类有参或无参构造。
3.子类可以继承父类的静态方法和静态属性,但是不能通过他们来体现多态性。因为仅仅是继承,没有重写(覆盖)而是隐藏。

方法重写:
子类继承父类后,想要有自己的特有的方法,就重写父类中的方法。

重写注意事项:
1.父类私有内容,子类重写不了
2.子类重写父类方法时必须要大于父类中方法的访问权限

继承中需要注意的事项:
1.java中不支持多继承,但是可以实现多接口,和多层继承

权限修饰符:

public 任意类
protected 不同包的子类
缺省 同一个包中的子类或者无关类
private 被修饰的方法访问和属性只能在本类中

状态修饰符:

final:可以修饰成员方法,成员变量,类.
被final修饰的方法不可以被重写
被final修改的类不能被继承
被final修饰的基本类型变量==常量,值不可以被修改
被final修饰的引用类型变量的引用地址不可以变,但是引用变量所指向的值可以改变。

static:可以修饰成员变量和成员方法
为什么static不能修饰局部变量,因为局部变量在方法中,随方法进栈执行后消失,而static修饰的变量或方法从属于类,生命周期和类一样长,所以用static修饰局部变量会有逻辑上的错误

static修饰特点:
1.被类的所有对象共享
2.可以通过类名调用

static的访问特点:
静态成员方法只能访问静态成员

static注意事项:
1.static中不能使用this和super关键字,因为static属于类,而this和super属于对象引用。

多态

什么是多态?
同一个对象不同时刻表现出来的不同行为,形态,多态性是面向对象编程的一种特性,和方法无关。
简单说,就是同样的一个方法能够根据输入数据的不同,做出不同的处理,即方法的
重载——有不同的参数列表(静态多态性)
而当子类继承自父类的相同方法,输入数据一样,但要做出有别于父类的响应时,你就要覆盖父类方法,
即在子类中重写该方法——相同参数,不同实现(动态多态性)

实现条件:
1.有继承关系 fu zi类。
2.有方法重写
3.父类引用指向子类对象 动物 animal = new Cat();

多态成员访问特点:
成员变量:编译看左边,执行看左边——静态编译
成员方法:编译看左边,执行看右边——动态编译

为什么成员变量和成员方法的访问不一样呢?
因为方法有重写,而变量没有。

多态的好处和弊端?
好处:
定义方法时,用父类型作为形参,在使用时只需要传入不同的子类对象就可以
有不同的操作,这是多态的动态体现。通过方法的重写完成。
弊端:
不能使用子类的特有方法,只能考虑向下转型。
如:Animal a = new Cat(); ((Cat).a).catchMouse();

多态的转型:
向上转型:子类对象指向父类引用
Animal a = new Cat();
向下转型:
Cat c = ((Cat).a);

多态——静态动态绑定机制

静态绑定:又称前期绑定
在程序运行前就已经知道方法是属于那个类的,在编译的时候就可以链接到类中,定位到这个方法。
在Java中,final、private、static修饰的方法以及构造函数和子类中的成员变量都是静态绑定的,不需程序运行,不需具体的实例对象就可以知道这个方法的具体内容。
因为final或private修饰的父类中的变量或方法,不能被子类中修改或访问所以多态调用时仍然是父类中的方法

例:Father() f = new Son(); f.say(); Son继承Father,重写了父类的say()方法

动态绑定:又称后期绑定

编译看左边:在代码编译阶段,编译器会通过 声明对象的类型(即引用本身的类型)在方法区中该类型的方法表中查找匹配方法(最佳匹配法:参数类型最接近的被调用),如果有则被调用(此处就是根据左边的引用变量类型来在父类中的方法表,而father类方法表中没有子类新增的方法,所以会报错)。

运行看右边:上面编译阶段在 声明对象类型 的方法表中查找方法,只是为了安全的通过编译(也是为了检验方法是否是存在的)。
在执行 Father f=new Son(); 这一句时创建了一个Son实例对象,然后在 f.say() 调用方法时,JVM会把刚才的son对象压入操作数栈,用它来进行调用。
而用实例对象进行方法调用的过程就是动态绑定:根据实例对象所属的类型去查找它方法,找到匹配的方法进行匹配。
子类如果重写了父类的方法,则方法表中同名项会指向子类的方法代码;如果没有重写,则按照父类中的方法表顺序保存在子类方法表中。

故此:动态绑定根据对象的类型的方法表查找方法是一定会匹配(因为编译时在父类方法表中以及查找并匹配成功了,说明方法是存在的。这也解释了为何向上转型时父类引用不能调用子类新增的方法:在父类方法表中必须先对这个方法的存在性进行检验,如果在运行时才检验就容易出危险——可能子类中也没有这个方法)。

示例代码:

public class AnimalDemo {
    public static void main(String[] args) {
        //父类引用指向子类对象,也是向上转型,编译看左边,运行也看左边
        Animal a = new Cat();
        //父类中的age
        System.out.println(a.age);
        //子类中的age
        System.out.println(((Cat) a).age);
        //Animal向下转型为Cat类型
        System.out.println(((Cat) a).weight);
        a.eat();//重写的子类方法
        a.Animal();//父类独有的方法
        //为什么编译不通过,因为子类中特有方法
        //在编译时是看Animal a这个引用变量的类型中有没有plagGame();
        //所以会报错,必须向下转型为Cat才能在方法表中找到playGame()方法
        //a.palyGame();
        ((Cat) a).playGame();//子类独有的方法,但是目前的引用是父类所以需要向下转型
    }
}

多态总结:
一、使用父类类型的引用指向子类的对象;
二、该引用只能调用父类中定义的方法和变量;
三、如果子类中重写了父类中的一个方法,那么在调用这个方法的时候,将会调用子类中的这个方法;(动态连接、动态调用)
四、变量不能被重写(覆盖),”重写“的概念只针对方法,如果在子类中”重写“了父类中的变量,那么在编译时会报错。
五、除了Static和Final(Private方法属于final,和final一样,不能被重写)方法,其他所有方法都是动态绑定;

抽象类:

在java中一个没有方法体的方法应该定义为抽象方法,而类中如果有抽象方法,该类必须定义为抽象类

抽象类特点:
类和方法都必须要用abstract修饰

接口概述:
接口是一种公共规范标准,java中的接口更多体现在对行为的抽象上

接口的特点:
1.接口用关键字interface修饰
2.类实现接口用implements表示
3.接口不能实例化
接口如何实例化?参考多态的方式,通过实现类对象的实例化,这就是接口多态
多态的形式;具体类多态、抽象类多态、接口多态
4.接口中的变量默认被public static final修饰。不可改变
5.接口没有构造方法,因为不能直接实例化,只能通过实现类的多态特性来实例化接口。
6.接口中的方法只能是抽象方法,默认被public abstract修饰。

访问修饰符和状态修饰符

访问修饰符:
public :任何包任何类下都可以访问
protected:任何包下的子类都可以访问—不能修饰类、接口和抽象方法
默认也叫缺省(不写):同包下的不同类可以访问
private:本类下面可以访问----不能修饰类、接口和抽象方法

作用范围:修饰类、成员方法、成员变量(没有局部变量哦!!!!!!!)

非访问修饰符(状态修饰符):
static:创建静态变量和方法----不能修饰类
final:修饰类不可继承、修饰方法不可重写、修饰变量为常量不可以修改----全部能修饰(除了接口和抽象类)
abstract:定义抽象方法、完成抽象类的定义----不能修饰变量
作用范围:可以修饰类、成员方法、变量(局部变量和成员变量)

注意:
1.接口中方法默认 public abstract 修饰、变量默认public final static修饰(不过接口一般用于对方法的抽象,属性的定义可以放到抽象类中),接口的修饰只能是public和缺省。

2.一般类的权限修饰符只能是public 和 缺省,
成员内部类相当于成员方法可以用四种权限修饰符和static、final、abstract修饰;
局部内部类定义在方法体里的类,只能被final和abstract修饰

3.成员方法的修饰可以用四种权限修饰符和上面三种状态修饰符; 成员变量的修饰可以用四种权限修饰符和static 、final

4 局部变量本身就是在包裹它的方法的权限里,如果再定义权限就会冲突,所以只能用final修饰。

5.final修饰的变量必须要由用户显示赋值,不能由jvm自己初始化默认。

6.类,抽象类,接口只能使用public 和 缺省来修饰,类可以被final修饰,而抽象类必须用abstract修饰。

7.abstract不能和final、private、static一起用(不能重写或继承、不能访问、类名调用没有方法体)

匿名内部类

定义格式:new Interface || 父类 (){
public void method(){
重写父类或接口中的方法
}
}

基本类型包装类

为什么要有包装类?
原因:1.方便操作基本数据类型 2.符合面向对象编程

对应规则:
下面俩个不一样,其余六种基本数据类型只需首字母大写即可
int 对应 Integer
char 对应 Character

Integer类的构造方法
Integer i = 123;(自动装箱)
Integer i = Integer.valueof(123);
integer i = Integer.valueof(“123”);

Integer转String
1.例:Integer i = 1; String s = String.valueof(i);
2. String s = i+"";(最常用最方便)

String转Integer
1.例:String s = “123”; Integer i = Integer.valueof(s);
2.Integer i = Integer.parseInt(s);

自动装箱拆箱
装:基本到包装类
拆: 包装到基本类型
例:
Integer i = 1;自动装箱
int in = i; 自动拆箱,中间的操作为:int in = i.intvalue();
Integer i = 1;
Integer i1 = 2;
Integer i2 = i + i1;包含了自动装箱和自动拆箱;中间的操作为 Integer对象先拆为int 然后int类型相加在包装成包装类。

关于Integer的注意点:
byte常量池:
当直接Integer i = number;(number<128)时 ,jvm就会在byte常量池中直接定义一个数字,如果后面再定义相同number就直接从常量池中拿出来,不用去新建一个number
反之如果超出了128也就是常量池的范围那么就会重新创建一个Integer对象,所以 在==比较地址值时一个是常量池中的常量,一个是新的Integer对象,返回false。而Integer重写了equals方法所以任然比较的是内容所以返回true。

        Integer it = new Integer(100);
        Integer it1 = new Integer(100);
        System.out.println(it1 == it);//false
        System.out.println(it1.equals(it));//true

        Integer it2 = 127;
        Integer it3 = 127;
        System.out.println(it2 == it3);//true
        System.out.println(it2.equals(it3));//true

        Integer it4 = 128;
        Integer it5 = 128;
        System.out.println(it4 == it5);//false
        System.out.println(it4.equals(it5));//true

字符串的排序:

异常

在这里插入图片描述

分类:
错误:由硬件或环境出现的问题,无法解决

异常:
1.编译时异常:必须处理否则无法通过编译

发生条件:一般和本地资源信息有关系
时间解析、读取本地文件、访问本地数据库

2.运行时异常:无需显示处理,也可以和编译异常一样处理

发生条件:一般和代码(参数)有关系
空指针异常、越界异常、数学异常

jvm默认处理异常的方式:
用户自己不处理异常,jvm会以默认方式处理异常
方式:1.打印异常信息 (e.printStackTrace()) 2.终止jvm

用户处理异常方式:
1.捕获

执行流程:程序从try中代码块开始运行,遇到异常生成异常对象,被匹配的异常catch捕获,处理异常,程序继续执行。
注意:

  • 如果try里面有多个语句块,如果第一个语句块遇到异常了,则直接跳转到catch语句块中。当catch语句块执行完毕后就表示异常处理完毕,不会再次回到try里面执行没有执行到的语句。
  • catch块越向下抛出的异常应该大于上面
  • finall块不管有没有遇到异常都会得到执行
try{
       可能出现异常代码
}catch(异常类名1 变量名){
       异常处理代码
}catch(异常类名1 变量名){
	   异常处理代码
}finally{
       不管是否出现异常都执行
}

2.抛出
抛出:有时候的异常我们处理不了所以要抛出,但是不能从根本解决异常,具体是谁调用谁处理。
如果抛出是在方法中进行的那么异常后面的代码会被弹栈,不会被执行。
综合前面的try catch可以发现在try块或者被抛出异常的方法中一旦异常发生之后的代码都不会得到执行

注意:
如果是编译异常:必须手动抛出,否则编译通过不了
如果是运行时异常:抛出可以省略,因为编译可以通过,最终交给jvm抛出。


为什么要有自定义异常:

自定义异常:
为了在出错时的提示信息更加见名知意,如果所有异常都给你抛一个Exception.那几乎没什么作用。

简单总结:Java中定义这么多的异常其实就是为了他的名字,让用户了解错在哪里。所以当当前异常类名不能或者不能很好的提示用户时,用户需要自定义异常

步骤:
1.定义自定义异常类名,做到见名之意且以Exception结尾
2.继承RunTimeException or Exception
3.定义有参和无参构造

总结:
什么时候throws什么时候try catch?
以用户需不需要发生异常后代码是否仍需执行为标准

throws和throw的区别?
throw 关键字的用法
直接给调用者一个异常对象,告诉调用者此处出现了问题
格式:throw new 异常类名();在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值