Java继承概述
1.多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些相同属性和行为,只要继承那个类即可。
2.在Java中通过extends关键字可以实现类与类的继承。
例如:class 子类名 extends 父类名 {}
3.单独的这个类称为父类,基类或者超类;这多个类可以称为子类或者派生类。
4.有了继承以后,我们定义一个类的时候,可以在一个已经存在的类的基础上,还可以定义自己的新成员
类的继承格式
在 Java 中通过 extends 关键字可以申明一个类是从另外一个类继承而来的,一般形式如下:
class 父类 {
}
class 子类 extends 父类 {
}
继承案例
动物父类
ublic class Animal {
private Integer age; //
public Animal(){
System.out.println("Animal construct method");
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public void eat(){
System.out.println("eat food");
}
}
狗子类
public class Dog extends Animal{ //class 子类名 extends 父类名
private String color; //毛色, /可以定义特有属性
public Dog(String color){ //可以定义特有属性
this.color = color;
}
public void run(){ //可以定义特有属性
System.out.println("Dog is running");
}
@Override
public void eat(){
System.out.println("dog eat bone"); //可以重写父类有的方法
}
}
继承的特性
- 子类拥有父类非 private 的属性、方法。
- 子类可以拥有自己的属性和方法,即子类可以对父类进行扩展。
- 子类可以用自己的方式实现父类的方法。
- Java 的继承是单继承,但是可以多重继承,单继承就是一个子类只能继承一个父类,多重继承就是,例如 A 类继承 B 类,B 类继承 C
类,所以按照关系就是 C 类是 B 类的父类,B 类是 A 类的父类,这是 Java 继承区别于 C++ 继承的一个特性。 - 提高了类之间的耦合性(继承的缺点,耦合度高就会造成代码之间的联系越紧密,代码独立性越差)
从这两段代码可以看出来,代码存在重复了,导致后果就是代码量大且臃肿,而且维护性不高(维护性主要是后期需要修改的时候,就需要修改很多的代码,容易出错),所以要从根本上解决这两段代码的问题,就需要继承,将两段代码中相同的部分提取出来组成 一个父类,如果有相同的方法和属性,则不必重复
继承类型
super 与 this 关键字
super关键字:我们可以通过super关键字来实现对父类成员的访问,用来引用当前对象的父类。
this关键字:指向自己的引用。
class Animal {
void eat() {
System.out.println("animal : eat");
}
}
class Dog extends Animal {
void eat() {
System.out.println("dog : eat");
}
void eatTest() {
this.eat(); // this 调用自己的方法
super.eat(); // super 调用父类方法
}
}
public class Test {
public static void main(String[] args) {
Animal a = new Animal();
a.eat();
Dog d = new Dog();
d.eatTest();
}
}
运行结果
animal : eat
dog : eat
animal : eat
final关键字
final 关键字声明类可以把类定义为不能继承的,即最终类;或者用于修饰方法,该方法不能被子类重写:
声明类:
final class 类名 {//类体}
声明方法:
修饰符(public/private/default/protected) final 返回值类型 方法名(){//方法体}
抽象类
抽象类
- 抽象类除了不能实例化对象之外,类的其它功能依然存在,成员变量、成员方法和构造方法的访问方式和普通类一样。
- 由于抽象类不能实例化对象,所以抽象类必须被继承,才能被使用
- 抽象类一般用来作为一个父类,但是里面可以有方法是抽象的,以让子类来实现。
- abstract 修饰符,表示这个类是一个抽象类
-
- 抽象类和普通类的区别: 抽象类中可以有抽象方法(只有方法定义,没有方法体,并且抽象类无法实例化)
抽象方法
- 抽象类和普通类的区别: 抽象类中可以有抽象方法(只有方法定义,没有方法体,并且抽象类无法实例化)
- 如果你想设计这样一个类,该类包含一个特别的成员方法,该方法的具体实现由它的子类确定,那么你可以在父类中声明该方法为抽象方法。
- Abstract 关键字同样可以用来声明抽象方法,抽象方法只包含一个方法名,而没有方法体。
- 抽象方法没有定义,方法名后面直接跟一个分号,而不是花括号。
抽象类的声明
public abstract class AbstractPerson {
public String name;
public int age;
//abstract 声明这个方法是一个抽象方法
public abstract void say();
public void eat() {
System.out.println("正在吃饭......");
}
}
继承了抽象类的子类
public class JapaneseExtendsAbstractPerson extends AbstractPerson{
/**
* 子类中必须实现抽象类中的抽象方法
*/
@Override
public void say() {
System.out.println("雅蠛蝶");
}
}
抽象类总结规定
-
抽象类不能被实例化(初学者很容易犯的错),如果被实例化,就会报错,编译无法通过。只有抽象类的非抽象子类可以创建对象。
-
抽象类中不一定包含抽象方法,但是有抽象方法的类必定是抽象类。
-
抽象类中的抽象方法只是声明,不包含方法体,就是不给出方法的具体实现也就是方法的具体功能。
-
构造方法,类方法(用 static 修饰的方法)不能声明为抽象方法。
-
抽象类的子类必须给出抽象类中的抽象方法的具体实现,除非该子类也是抽象类。
异常及其异常处理
异常的结构图
1.所有的异常都是从Throwable继承而来的,是所有异常的共同祖先。
2.Throwable有两个子类,Error和Exception。 错误: 错误不是异常,而是脱离程序员控制的问题。错误在代码中通常被忽略。例如,当栈溢出时,一个错误就发生了,它们在编译也检查不到的
3.Exception,是另外一个非常重要的异常子类。它规定的异常是程序本身可以处理的异常。异常和错误的区别是,异常是可以被处理的,而错误是没法处理的。**
4 检查性异常:最具代表的检查性异常是用户错误或问题引起的异常,这是程序员无法预见的。例如要打开一个不存在文件时,一个异常就发生了,这些异常在编译时不能被简单地忽略。
5运行时异常: 运行时异常是可能被程序员避免的异常。与检查性异常相反,运行时异常可以在编译时被忽略。
6.Exception是所以异常的父类,可以捕捉所有异常
异常发生的原因有很多,通常包含以下几大类:
-
用户输入了非法数据
-
要打开的文件不存在。
-
网络通信时连接中断,或者JVM内存溢出。
这些异常有的是因为用户错误引起,有的是程序错误引起的,还有其它一些是因为物理错误引起的。
常见的异常
java.lang.*下的异常:
1、Java.lang.NullPointerException
空指针异常:调用了未经初始化的对象或者是不存在的对象。
2、 java.lang.ClassNotFoundException
类不存在异常:类的名称和路径不正确。
3、 java.lang.NumberFormatException
字符串转换为数字异常。
4、java.lang.IndexOutOfBoundsException
数组下标越界异常。
5、java.lang.IllegalArgumentException
不合法的参数异常。
6、java.lang.IllegalAccessException
没有访问权限异常。
7、java.lang.ArithmeticException
数学运算异常。
8、java.lang.ClassCastException
数据类型转换异常。
9、java.lang.InterruptedException
线程中断异常。
10、java.lang.OutOfMemoryException
内容不足异常。
11、java.lang.NoClassDefFoundException
类未定义异常。
12、java.lang.NoSuchMethodException
方法不存在异常。
13、java.lang.NoSuchFiledException
属性不存在异常。
java.io.*下的异常:
14、Java.io.IOException
输入输出异常。
15、java.io.FileNotFoundException
文件不存在异常。
java.net.*下的异常:
16、Java.net.ConnectException
网络连接异常。
17、Java.net.SocketTimeoutException
网络连接超时异常。
java.rmi.*下的异常:
18、Java.rmi.ServerRuntimeException
服务器运行异常。
java.text.*下的异常:
19、Java.sql.SQLException
sql执行异常。
java.text.*下的异常:
20、Java.text.ParseException
转换异常。
捕获异常
使用 try 和 catch 关键字可以捕获异常。try/catch 代码块放在异常可能发生的地方。
try/catch代码块中的代码称为保护代码,使用 try/catch 的语法如下
try
{
// 程序代码
}catch(ExceptionName e1)
{
//Catch 块
}
Catch 语句包含要捕获异常类型的声明。当保护代码块中发生一个异常时,try 后面的 catch 块就会被检查。
如果发生的异常包含在 catch 块中,异常会被传递到该 catch 块,这和传递一个参数到方法是一样。
实例
下面的例子中声明有两个元素的一个数组,当代码试图访问数组的第三个元素的时候就会抛出一个异常。
// 文件名 : ExcepTest.java
import java.io.*;
public class ExcepTest{
public static void main(String args[]){
try{
int a[] = new int[2];
System.out.println("Access element three :" + a[3]);
}catch(ArrayIndexOutOfBoundsException e){
System.out.println("Exception thrown :" + e);
}
System.out.println("Out of the block");
}
}
编译结果
Exception thrown :java.lang.ArrayIndexOutOfBoundsException: 3
Out of the block
多重捕获块
一个 try 代码块后面跟随多个 catch 代码块的情况就叫多重捕获。
多重捕获块的语法如下所示:
try{
// 程序代码
}catch(异常类型1 异常的变量名1){
// 程序代码
}catch(异常类型2 异常的变量名2){
// 程序代码
}catch(异常类型2 异常的变量名2){
// 程序代码
}
上面的代码段包含了 3 个 catch块。
可以在 try 语句后面添加任意数量的 catch 块。
如果保护代码中发生异常,异常被抛给第一个 catch 块。
如果抛出异常的数据类型与 ExceptionType1 匹配,它在这里就会被捕获。
如果不匹配,它会被传递给第二个 catch 块。
如此,直到异常被捕获或者通过所有的 catch 块。
实例
该实例展示了怎么使用多重 try/catch。
try {
file = new FileInputStream(fileName);
x = (byte) file.read();
} catch(FileNotFoundException f) { // Not valid!
f.printStackTrace();
return -1;
} catch(IOException i) {
i.printStackTrace();
return -1;
}
finally关键字
finally 关键字用来创建在 try 代码块后面执行的代码块。
无论是否发生异常,finally 代码块中的代码总会被执行。
在 finally 代码块中,可以运行清理类型等收尾善后性质的语句。
finally 代码块出现在 catch 代码块最后,语法如下:
try{
// 程序代码
}catch(异常类型1 异常的变量名1){
// 程序代码
}catch(异常类型2 异常的变量名2){
// 程序代码
}finally{
// 程序代码
}
实例
public class ExcepTest{
public static void main(String args[]){
int a[] = new int[2];
try{
System.out.println("Access element three :" + a[3]);
}catch(ArrayIndexOutOfBoundsException e){
System.out.println("Exception thrown :" + e);
}
finally{
a[0] = 6;
System.out.println("First element value: " +a[0]);
System.out.println("The finally statement is executed");
}
}
}
以上实例编译运行结果如下:
Exception thrown :java.lang.ArrayIndexOutOfBoundsException: 3
First element value: 6
The finally statement is executed
注意下面事项:
catch 不能独立于 try 存在。
在 try/catch 后面添加 finally 块并非强制性要求的。
try 代码后不能既没 catch 块也没 finally 块。
try, catch, finally 块之间不能添加任何代码。
抛出异常
抛异常可以直接抛给jvm: 就是说,在main方法中,不对可能出现异常的代码进行try-catch
下层方法可以把异常抛给上层调用者
比如:定义一个方法,求商,方法声明会抛出异常,则在调用该方法时会出现提醒让其使用try-catch
public static int divide(int a,int b) throws Exception{
return a/b;
}
然后有两种情况使用
情况一, 可以选择继续往上抛
// divide方法的调用者就能获得提示:如何处理异常
// 可以选择继续往上抛
main thows Exception {
divide(5,0);
}
情况二,也可以选择将异常抓住,不再外抛了
main{
try{
divide(5,0);
}catch(Exception e){
sysout(e.getMessage());
}
}
throw 抛出异常
当程序运行时数据出现错误或者我们不希望发生的情况出现的话,可以通过抛出异常来处理。
异常抛出语法:
throw new 异常类();
在 /home/project/ 目录下新建 ThrowTest.java
public class ThrowTest {
public static void main(String[] args) {
Integer a = 1;
Integer b = null;
//当a或者b为null时,抛出异常
if (a == null || b == null) {
throw new NullPointerException();
} else {
System.out.println(a + b);
}
}
}
$ javac ThrowTest.java
$ java ThrowTest
Exception in thread "main" java.lang.NullPointerException
at ThrowTest.main(ThrowTest.java:8)
throws 声明异常
throws 用于声明异常,表示该方法可能会抛出的异常。如果声明的异常中包括 checked 异常(受检异常),那么调用者必须捕获处理该异常或者使用 throws 继续向上抛出。throws 位于方法体前,多个异常之间使用 , 分割。
修改 /home/project/ 下的 ThrowsTest.java:
import java.io.FileInputStream;
import java.io.FileNotFoundException;
public class ThrowsTest {
public static void main(String[] args) throws FileNotFoundException {
//由方法的调用者捕获异常或者继续向上抛出
throwsTest();
}
public static void throwsTest() throws FileNotFoundException {
new FileInputStream("/home/project/shiyanlou.file");
}
}
编译运行:
$ javac ThrowsTest.java
$ java ThrowsTest
Exception in thread "main" java.io.FileNotFoundException: /home/project/shiyanlou.file (系统找不到指定的路径。)
at java.io.FileInputStream.open0(Native Method)
at java.io.FileInputStream.open(FileInputStream.java:195)
at java.io.FileInputStream.<init>(FileInputStream.java:138)
at java.io.FileInputStream.<init>(FileInputStream.java:93)
at ThrowsTest.throwsTest(ThrowsTest.java:13)
at ThrowsTest.main(ThrowsTest.java:8)
[copy]