JAVA中继承与多态、抽象类与接口、异常操作以及I/O操作内容

继承

public class Apple extends Fruit {
  public static void main(String[] args) {
  }
}
class Fruit {
public Fruit(String name) {
     System.out.println("Fruit's constructor is invoked");
   }
}


这个代码段是错误的,Apple中没有显示调用父类Fruit中的语句,Apple一定会隐式调用父类的无参方法,但是Fruit中提供了一个有参数的构造方法,
就不会自动获得一个无参的默认构造方法,子类Apple无法调用父类构造方法
设计类的原则:无论需不需要,都写一个无参数的构造方法以避免这种错误

方法重写:

子类从父类中继承方法。有时子类需要修改父类中定义的实例方法的实现,这个操作称为重写
实现重写的条件:两同两小一大的原则
两同:指子类和父类的方法名和参数完全相同
两小:指子类方法的返回类型比父类的同名方法返回类型相同或更小;指子类同名方法抛出的异常更小或相同
一大:指子类方法的可见性(访问权限)修饰符比父类同名方法范围大或相同(如父类是默认,子类是public)
常见重写的方式:
方法名相同
参数列表相同
返回值类型相同
静态方法可以被继承,不能被重写
重载与重写:重载意味着使用相同的名字但是不同的方法签名来定义多个方法;重写意味着在子类中提供一个对父类已有方法的新的实现
Java中的每个类都源于java.lang.Object类,如果在定义一个类时没有指定继承性,那么这个类的父亲就默认是Object
Public class person等价于public class Person extends Object
在Java中如果要输出某个对象实例的有关信息,可以试一试它的toString()方法
toString()方法:
在Object类中定义了public属性的toString()方法,而Object是所有类的直接或间接父亲,而该方法会被子类继承。默认的toString()方法返回的结果是类似于类名@15037e5这样的字符串
在程序设计中建议重写to String()方法:
public String toString(){ ... }

对象转换


课程中已使用过转换运算把一种基本类型变量转换为另一种基本类型。也可以使用转换把一种类类型的对象转换为继承体系结构中的另一种类类型的对象,在基本数据类型转换中有隐式转换和强制转换,对象转换也有类似概念
类可以被隐式的自动的转换为其父类的类型

Object o = new Student() // 隐式转换,也称为向上转型
Student b = o; //编译错误
Student对象总是Object的实例,但是,Object对象不一定是Student的实例
Student b = (Student)o; //显示(强制)转换
Instanceof运算符


使用该运算符来检测一个对象是否是一个类的实例:

Fruit f = new Apple();
Apple s = (Apple)f; // 讲Fruit的实例f赋值给Apple的变量s
f instanceof Apple 将返回 true
f instanceof Orange 将返回false


ps:为了更好的理解类型转换,可以认为它们类似于水果、苹果、橘子之间的关系,其中水果类是苹果类和橘子类的父类。苹果是水果,所以总是可以将Apple的实例安全地赋值给Fruit变量。但是,水果不一定是苹果,所以,必须进行显示转换才能将Fruit的实例赋值给Apple的变量

多态

多态的含义:多态意味着父类的变量可以指向子类对象(向上转型),当调用该父类变量的一些成员方法,其行为可以表现为子类同名方法(方法重写)的行为特征,而不是父类同名方法的特征。这样就会出现这样一个情况:相同类型的变量,调用同一个方法时呈现出不同的行为特征,所以称为多态
代码例子

package ch01;

public class PolyDemo1 {
    public static void main(String[] args) {
        myPrint(new Object());
        myPrint(new Person());
        myPrint(new Student());
        myPrint(new GraduteStudent());
        
    }
    public static void myPrint(Object o) {
        System.out.println(o.toString());
    }
}
    
    class Person {
        public String toString() {
            return "Person";
        }
    }
    class Student extends Person {
        public String toString() {
            return "Student";
        }
    }
    class GraduteStudent extends Student {
     public String toString() {
             return "GraduteStudent";
         }
     }


     
多态要点
1、父类定义需要被重写的方法
2、子类重写父类的方法
3、将子类的对象实例赋值给父类类型的变量,则可以通过该变量调用被重写的方法,自动调用子类的不同的重写版本

动态绑定


如果对象0调用一个方法p,那么Java虚拟机会依次在C1、C2、...、Cn-1、Cn中(Cn是最通用的类即在Java中是Object类,C1是最特殊的类)查找方法p的实现,直到找到为止。一旦找到一个实现,就停止查找并调用这个第一次找到的实现(从最远端的子类中开始找)
多态的应用场景
为了实现多态,就需要定义一个合适的父类,并在父类中定义你需要的方法,然后让子类继承这个父类,并重写对应方法,这样就能实现一个具有较好扩展性的功能模块

ArrayList


数组列表,一种类似于数组的列表,但其为动态大小,可用于存储不定数量的对象。早期版本的ArrayList很多方法的参数类型都是Object类
数组长度是用.length()方法,这个是用.size()
ArrayList初步版本
代码例子

package ch01;

import java.util.ArrayList;

public class TestArrayList {
    public static void main(String[] args) {
        ArrayList cityList = new ArrayList();
        cityList.add("广州");
        cityList.add("南京");
        cityList.add("北京");
        System.out.println(cityList.size());
        System.out.println(cityList.contains("南京"));//检查是否存在
        System.out.println(cityList.indexOf("南京"));//下标
        System.out.println(cityList.toString());
        cityList.add(1,"深圳");//添加元素
        System.out.println(cityList.toString());
        cityList.remove(1);//移除
        System.out.println(cityList.toString());
        for(int i = 0; i<cityList.size(); i++) {
            System.out.println(cityList.get(i).toString());
            //加不加toString输出都一样
        }
        
        
    }

}


ArrayList泛型版本


泛型是对Java语言的类型系统的一种扩展,可以将数据类型参数化,可以定义泛型类和泛型方法。泛型就类似与方法中的形参,可以把类型参数看作是使用参数化类型时指定的类型的一个占位符,就像方法的形式参数时运行时传递的值的占位符一样
ArrayList泛型版本用尖括号来指定类型参数<E>
ArrayList初步版本:java.util.ArrayList
ArrayList泛型版本:java.util.ArrayList<E>
(原始版本可以看作参数E为Object)
简写:ArrayList<String> cityList = new ArrayList<>();
ArrayList<GeometricObject> list = new ArrayList<>();
list.add(new Circle());
list.add(new Rectangle());
数组/ArrayList转换
数组转为ArrayList:
String[] array = {"red", "green", "blus"};
ArrayList<String> list = new ArrayList<>(Arrays.asList(array)); //asList方法
ArrayList转为数组
String[] array1 = new String[list.size()]; //数组要预先根据数组列表的数量确定好数组大小
list.toArray(array1); //toArray方法,参数是数组
对于数组列表,java.util.collections类中有许多方法,有求最大值最小值随机排序等
数组遍历
for(Integer i : array) {
   System.out.println(i);
} // 类型 i : 数组名

抽象类

抽象方法

只有方法定义没有方法体,但不等同于方法体为空
定义一个抽象方法
例 getArea定义
public abstract double getArea(); //直接分号结束,没有方法体
抽象类
有抽象方法的类,必须定义为抽象类
public abstract class GeometricObject{...}
抽象类中可以没有抽象方法
抽象类不能进行实例化,但仍然可以定义它的构造方法,这个构造方法被它子类的构造方法中调用
抽象类不能使用new操作符来实例化,抽象类只分配了在栈中的引用,没有分配堆中的内存,可以定义构造方法,但该构造方法不是用于其自身的实例化
protected GeometricObject() {
dateCreated = new java.util.Date();
} //用protected修饰构造方法,访问者必须是子类,这样定义即使子类不在同一个包中也有办法进行访问调用
不能使用new操作符从一个抽象类创建一个实例 ,但是抽象类可以被用作一种数据类型。因此,下面的语句创建一个元素是GaometricObject类型的数组 ,这个语句是正确的:
GeometricObject[] geo = new GeometricObject[10]; // 因为实例化的不是这个类而是这个类型的数组
抽象类的子类必须重写其所有的抽象方法,否则子类也必须为抽象类;
GeometricObject g = new Circle();
g.getArea(); // 执行Circle的getArea、方法实现

接口

在Java中,接口是一种与类相似的结构,在使用上和抽象类较为相似。例如,可以使用接口作为引用变量的数据类型或子类实例向上转型的传值等,同样也不能使用new操作符创建接口的实例
定义接口
为了区分接口和类,Java采用下面的语法来定义接口:

public interface InterfaceName {
  constant declarations;
 abstract method signatures;
}
public interface Edible {
   public abstract String howToEat():
}


接口可以看作是一种特殊的类
但是接口的子类不叫继承,子类称为实现(implements)接口
子类实现接口不受单重继承限制,可以继承一个类,同时实现多个接口,不同接口之间用逗号隔开
抽象类和子类之间有明显的共性,而接口则在使用语义上完全不同,接口是用来抽象对像
接口案例
定义一个接口Edible,表示是否可食用,接口中定义抽象方法howToEat,表示如何食用的行为,任何需要实现“如何食用”这个行为的类都可以使用implemens这个接口,这些子类之间可能相似,也可能毫无关系,但都有共同的行为“如何食用”
苹果橙子等水果以及鸡都是可食用的,但是不好将他们定义为这些类的父类,所以使用接口更为方便
接口是指明相关或者不相关类的多个对象的共同行为
接口中可以省略修饰符
public interface T1 {
  public static final int k = 1;
  public abstract void p();
}
等价于
public interface T1 {
  int k = 1;
  void p();
}
接口内定义的常量可以使用语法“接口名.常量名”(T1.K)
通过接口
制造了一种多态“框架”
添加实现代码
在合适的地方自动调用你的功能

异常的类别和处理

异常处理
异常处理使得程序可以处理非预期的情景,并且继续正常的处理
免检异常和比检异常
一类可以自由选择是否进行异常捕获
还有一类异常,规定了必须进行异常处理,否则程序不能进行编译
异常处理机制
Java中的异常处理包括声明异常、抛出异常以及捕获异常
手动抛出异常
throw new Exception();

Exception ex = new Exception("相关错误信息");
throw ex;
如果方法声明了一个必检异常,就必须在try-catch块中调用它
finally子句
无论异常是否产生,finally子句总是会被执行
try{
  statements;
}
catch(TheException ex){
  handling ex;
}
finally {
  finalStatements;
}
所以经常将一些资源回收语句放在finally中
自定义异常
java API中已经定义了大量的异常类
尽量使用API中的异常类
如果预定义的类不满足要求,要创建自定义异常类
通过扩展Exception类或其子类来创建自定义异常

I/O处理

文本I/O
文本文件和二进制文件区别
在底层,所有文件都是二进制的表示方式
文本文件是指那些用windows记事本或Linus下vi可以直接浏览编辑的文件,具有广泛的通用性。(java源文件)
除文本文件之外的文件都称为二进制文件,二进制文件可以完全按自己的方式来写数据,需要编写专门的程序来读取(class文件)
PrintWriter写文本数据
Scanner读取文本文件
两个都可以指定编码
PrintWriter output = new PrintWriter(file,UTF-8)
二进制I/O类的用法
InputStream
OutputStream
FileInputStream可使用下面的构造方法
public FileInputStream(String filename)
public FileInput Stream(File file)
FileOutputStream可使用下面的构造方法
pubilc FileOutputStream(String filename)
public FileOutputSream(File file)
public FileOutputStream(String filename, boolean append)
public FileOutputStream(File file, bollean append) 
这些类都有进行异常处理,所以使用时如果不做try-catch,就要加上throws IOException / Exception
处理二进流
read、write方法只能读写基本字节
DataInputStream和DataOutputStream提供了字节处理的增强功能,可以处理基本数据类型和字符串类型
使用DataInputStream/DataInputStream
数据流用于对已经存在的输入/输出流进行包装,以便在原始流中过滤数据。可以使用下面的构造方法来创建它们:
DataInputStream infile =
  new DataInputStream(new FileInputStream("in.dat"));
DataInputStream outfile = 
new DataInputStream(new FileInputStream("out.dat"));

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值