• Java基础-day18


    抽象类

    抽象类不可以用于创建对象 。 抽象类可以包含抽象方法 , 这些方法将在具体的子类中实现

    抽象类:一个非常抽象的父类,它都没有任何具体的实例

    抽象方法:利用abstract修饰符来定义的方法,之后,这个方法所属的类为抽象类

    public abstract class GeometricObject {     // 抽象类
        private String color = "white";
        private boolean isFilled;
        private java.util.Date dataCreated;
    
        protected GeometricObject(){
            dataCreated = new java.util.Date();
        }
    
        protected GeometricObject(String color, boolean isFilled){
            this.color = color;
            this.isFilled = isFilled;
            dataCreated = new java.util.Date();
        }
    
        public String getColor(){
            return color;
        }
    
        public void  setColor(String color){
            this.color = color;
        }
    
        public boolean getisFilled(){
            return isFilled;
        }
    
        public void setisFilled(boolean isFilled){
            this.isFilled = isFilled;
        }
    
        public java.util.Date getDataCreated(){
            return dataCreated;
        }
    
        @Override
        public String toString(){
            return "create on " + dataCreated + "
    color:" + color +
                    " and filled: " + isFilled;
        }
    
        // 抽象方法
        public abstract double getArea();
        public abstract double getPerimeter();
    
    }
    

    Snipaste_2020-05-02_15-10-26

    1. 抽象类和常规类很像 , 但是不能使用 new 操作符创建它的实例 。 抽象方法只有定义而没有实现 。 它的实现由子类提供 。 一个包含抽象方法的类必须声明为抽象类

    2. 抽象类的构造方法定义为 Protected , 因为它只被子类使用 。 创建一个具体子类的实例时 , 它的父类的构造方法被调用以初始化父类中定义的数据域

    为何要使用抽象方法

    Snipaste_2020-05-02_15-31-42

    JVM 在运行时根据对象的类型动态地决定调用哪一个方法

    抽象类的几点说明

    Snipaste_2020-05-02_15-36-51

    实例学习:抽象的Number类

    import java.math.BigDecimal;
    import java.math.BigInteger;
    import java.util.ArrayList;
    
    public class LargestNumber {
        public static void main(String[] args) {
            ArrayList<Number> list = new ArrayList<>();	// 创建一个Number对象的ArrayList
            list.add(4); // 向列表中增加一个 Integer 对象,通过拆箱操作,45自动转换为 Integer对象并增加到列表中
            list.add(4.5);		//  一个 Double 对象
            list.add(new BigInteger("199910017572"));	// 一个BigInteger对象
            list.add(new BigDecimal("3.505211992"));	// 一个BigDecimal对象
    
            System.out.println("The Largest is : " + getLargest(list));
        }
    	// 返回列表中的最大数值
        public static Number getLargest(ArrayList<Number> list){
            if(list.size() == 0 || list == null)
                return  null;
            Number number = list.get(0);        // 获得数组列表中的第一个元素
            for (int i = 1; i < list.size(); i++){
                // doubleValue()方法定义在Number类中,并在Number类的具体子类中得到实现 
                if(number.doubleValue() < list.get(i).doubleValue()){
                    number = list.get(i);
                }
            }
            return number;
        }
    }
    

    接口

    接口是一种与类相似的结构 , 只包含常量和抽象方法

    **接口在许多方面都与抽象类很相似 , 但是它的目的是指明相关或者不相关类的多个对象的共同行为 **

    修饰符 interface 接口名{
        /** 常量声明 */
        /** 方法签名 */
    }
    

    在 Java 中, 接口被看作是一种特殊的类 。就像常规类一样,**每个接口都被编译为独立的字节码文件 **

    可以使用接口作为引用变量的数据类型或类型转换的结果等 。 与抽象类相似 , 不能使用 new 操作符创建接口的实例

    类和接口之间的关系称为接口继承。 因为接口继承类继承本质上是相同的 , 所以我们将它们都简称为继承

    public class TestEdible {
        public static void main(String[] args) {
            Object[] objects={new Chicken(),new Tiger(),new Orange()};//创建对象数组
            for (int i=0;i<objects.length;i++){
                if (objects[i]instanceof Edible)
                    System.out.println(((Edible)objects[i]).howToEat());
                if (objects[i]instanceof Animal)
                    System.out.println(((Animal)objects[i]).sound());
            }
        }
    }
    
    interface Edible {					//设计一个Edible接口来明确一个对象是否是可食用的
        public abstract String howToEat();	//接口中方法格式固定:public abstract
    }
    
    abstract class Animal {				//抽象类Animal
        public abstract String sound();	//抽象方法(动物叫声)
    }
    
    class Chicken extends Animal implements Edible {//鸡肉类继承抽象的Animal类并实现Edible接口以表明小鸡是可食用的
        @Override
        public String sound() {
            return "Chicken:cock-a-doodle-doo";
        }//重写sound方法
    
        @Override
        public String howToEat() {
            return "Chicken:Fry it";
        }//重写howToEat方法
    }
    
    class Tiger extends Animal{//老虎类继承抽象的Animal类
        @Override
        public  String sound(){
            return "Tiger:RROOAARR";
        }//重写sound方法
    }
    
    abstract class Fruit implements Edible{//抽象类Fruit实现接口Edible,因为它不实现howToEat方法,所以Fruit类必须是抽象的
    }
    
    class Apple extends Fruit {//苹果类继承Fruit类(Fruit的子类必须实现howToEat方法)
        @Override
        public String howToEat(){
            return "Make apple cider";
        }//重写howToEat方法
    }
    
    class Orange extends Fruit{//橘子类继承水果类(Fruit的子类必须实现howToEat方法)
        @Override
        public String howToEat(){
            return "Orange:Make orange juice";
        }//重写howToEat方法
    }
    

    Snipaste_2020-05-02_16-43-34

    Comparable 接口

    Comparable 接口定义了 compareTo 方法 , 用于比较对象 。

    package java.lang;	// 在java.lang包中定义了比较对象的接口
    public interface Comparable<E>{
        public int compareTo(E o);
    }
    

    Comparable 接口是一个泛型接口 。 在实现该接口时 , 泛型类型 E 被替换成一种具体的类型

    Snipaste_2020-05-02_21-05-55

    可见,数字是可比较的 , 字符串是可比较的 , 日期也是如此

    System.out.println(new Integer(3).compareTo(new Integer(5)));
    System.out.println("ABC".compareTo("ABE"));
    java.util.Date date1 = new java.util.Date(2013, 1, 1);
    java.util.Date date2 = new java.util.Date(2012, 1, 1);
    System.out.println(date1.compareTo(date2));
    
    -1		//  因为 3 小于 5
    -2		//  因为 ABC 小于 ABE
    1		//  因为 datel 大于 date 2 
    

    对字符串数组和 Biglnteger对象数组进行排序的示例

    Java API 中的java.util.Arrays.sort(Object[])方法就可以使用compareTo方法来对数组中的对象进行比较和排序

    import java.math.BigInteger;
    
    public class SortComparableObjects {
        public static void main(String[] args) {
            String[] cities = {"ShanDong", "BeiJing", "AnHui", "TaiWan"};
            java.util.Arrays.sort(cities);
            for (String city : cities)
                System.out.print(city + " ");
            System.out.println();
    
            BigInteger[] hugeNumbers = {new BigInteger("22222222222"), new BigInteger("33333333333333"),
            new BigInteger("4444444444444444444444")};
            java.util.Arrays.sort(hugeNumbers);
            for (BigInteger number : hugeNumbers){
                System.out.print(number + " ");
            }
            System.out.println();
        }
    }
    
    AnHui BeiJing ShanDong TaiWan 
    22222222222 33333333333333 4444444444444444444444 
    

    不能使用 sort 方法来对一个 Rectangle 对象数组进行排序 , 因为 Rectangle 类没有实现接口 Comparable 。 然而 , 可以定义一个新的 Rectangle 类来实现 Comparable 。

    Snipaste_2020-05-02_21-30-15

    Snipaste_2020-05-02_21-30-25

    Snipaste_2020-05-02_21-48-56

    Snipaste_2020-05-02_22-08-33

    Cloneable接口

    Cloneable 接口给出了一个可克隆的对象

    package java.lang;
    public interface Cloneable{}
    

    这个接口是空的 。 一个带空体的接口称为标记接口 。一个标记接口**既不包括常量也不包括方法 **。 它用来表示一个类拥有某些特定的属性。

    Calender calendar = new GregorianCalender(2020, 5, 3);
    Calender calendar1 = calendar;	// 将 calendar 的引用复制给 calendarl,所以calendar和calendarl 都指向相同的 Calendar 对象
    Calender calendar2 = (Calendar)calendar.clone();  // 创建一个新对象,它是 calendar 的克隆,是内容相同的不同对象
    System.out.println("calendar == calendar1 is " + 
                      (calendar == calendar1));
    System.out.println("calendar == calendar2 is " +
                      (calendar == calendar2));
    System.out.println("calendar.equals(calendar2) is " +
                      calendar.equals(calendar2));
    
    calendar == calendar1 is true
    calendar == calendar2 is false
    calendar.equals(calendar2) is true
    

    为了定义一个自定义类来实现 Cloneable 接口 , 这个类必须覆盖 Object 类中的clone()方法

    public class House implements Cloneable, Comparable<House> {
        private int id;
        private double area;
        private java.util.Date whenBuilt;
        
        public House(int id, double area){
            this.id = id;
            this.area = area;
            whenBuilt = new java.util.Date();
        }
        
        public int getId(){
            return id;
        }
        
        public double getArea(){
            return area;
        }
        
        public java.util.Date getWhenBuilt(){
            return whenBuilt;
        }
        
        @Override
        public Object clone() throws CloneNotSupportedException{
            return super.clone();
        }
        
        @Override
        public int compareTo(House o){
            if (area > o.area)
                return 1;
            else  if (area < o.area)
                return -1;
            else  
                return 0;
        }
    }
    
    • House 类实现在 Object类中定义的 clone 方法 ,方法头是protected native Object clone() throws CloneNotSupportedException;,关键字 native 表明这个方法不是用 Java 写的 , 但它是 JVM 针对自身平台实现的。 关键字 protected 限定方法只能在同一个包内或在其子类中访问 。 由于这个原因 , House 类必须覆盖该方法并将它的可见性修饰符改为 public , 这样 , 该方法就可以在任何一个包中使用

    • 因为 Object 类中针对自身平台实现的 clone 方法完成了克隆对象的任务 , 所以 , 在House 类中的 clone 方法只要简单调用 super.clone()即可

    House house1 = new House(1, 1750.50);
    House house2 = (House)house1.clone(); // housel和house2是两个内容相同的不同对象
    

    Object 类中的 clone 方法将原始对象的每个数据域复制给目标对象 。 如果一个数据域是基本类型 , 复制的就是它的值。 如果一个数据域是对象 , 复制的就是该域的引用。这称为浅复制而不是深复制

    Snipaste_2020-05-03_08-46-57

    改为深复制

    public Object clone() throws CloneNotSupportedException{
        House houseClone = (House)super.clone();					// 浅复制
        houseClone.whenBuilt = (java.util.Date)(whenBuilt.clone());	// 深复制
        return houseClone;
    }
    

    接口与抽象类

    一个类可以实现多个接口 , 但是只能继承一个父类 。

    Snipaste_2020-05-03_09-02-43

    • Java 只允许为类的扩展做单一继承 , 但是允许使用接 n 做多重扩展 。
    public class NewClass extends BaseClass implements Interfase1, ..., InterfaceN {...}
    
    • 利用关键字 extends , 接口可以继承其他接口,这种接口叫做子接口
    public interface NewInterface extends Interface1, ..., InterfaceN{
        ...
    }		//一个实现 Newlnterface 的类必须实现在 Newlnterface , Interfacel, ..., 			InterfaceN中定义的抽象方法
    

    接口可以扩展其他接口而不是类 。 一个类可以扩展它的父类同时实现多个接口 。

    • 所有的类共享同一个根类 Object , 但是接口没有共同的根

    实例学习:Rational类

    设计一个 Rational 类 , 用于表示和处理有理数

    Snipaste_2020-05-03_09-19-03

    public class Rational extends Number implements Comparable<Rational> {
        private long numerator = 0;     // 分子
        private long denominator = 1;   // 分母
    
        public Rational(){
            this(0, 1);
        }
        public Rational(long numerator, long denominator){
            long a = Math.abs(numerator);
            long b = Math.abs(denominator);
            long gcd = gcd(a, b);
            this.numerator = ((numerator > 0) ? 1 : -1) * numerator / gcd;
            this.denominator = Math.abs(denominator) / gcd;
        }
    	// 利用递归求最大公因数
        private static long gcd(long numerator, long denominator){
            if (denominator == 0) return numerator;
            else return gcd(denominator, numerator % denominator);
        }
    
        public long getNumerator(){
            return numerator;
        }
    
        public long getDenominator(){
            return  denominator;
        }
    
        public Rational add(Rational secondRational){
            long n = numerator * secondRational.getDenominator() +
                    denominator * secondRational.getNumerator();
            long d = denominator * secondRational.getDenominator();
            return new Rational(n, d);
        }
    
        public Rational substract(Rational secondRational){
            long n = numerator * secondRational.getDenominator() -
                    denominator * secondRational.getNumerator();
            long d = denominator * secondRational.getDenominator();
            return new Rational(n, d);
        }
    
        public Rational multiply(Rational secondRational){
            long n = numerator * secondRational.getNumerator();
            long d = denominator * secondRational.getDenominator();
            return new Rational(n, d);
        }
    
        public Rational divide(Rational secondRational){
            long n = numerator * secondRational.getDenominator();
            long d = denominator * secondRational.getNumerator();
            return new Rational(n, d);
        }
    
        @Override
        public String toString(){       // 继承了 Object类
            if (denominator == 1)
                return numerator + "";
            else
                return numerator + "/" + denominator;
        }
        
        @Override
        public int intValue(){          // 重写Number类中的intValue方法
            return (int)doubleValue();
        }
        
        @Override
        public float floatValue(){
            return (float)doubleValue();
        }
        
        @Override
        public double doubleValue(){
            return numerator * 1.0 / denominator;
        }
        
        @Override
        public long longValue(){
            return (long)doubleValue();
        }
        
        @Override
        public int compareTo(Rational secondRational){
            if (this.substract(secondRational).getNumerator() > 0)
                return 1;
            else if (this.substract(secondRational).getNumerator() < 0)
                return -1;
            else return 0;
        }
    
    }
    
    public class TestRational {
        public static void main(String[] args) {
            Rational r1 = new Rational(4, 2);
            Rational r2 = new Rational(2, 3);
    
            System.out.println(r1 + " + " + r2 + " = " + r1.add(r2));
            System.out.println(r1 + " - " + r2 + " = " + r1.substract(r2));
            System.out.println(r1 + " * " + r2 + " = " + r1.multiply(r2));
            System.out.println(r1 + " / " + r2 + " = " + r1.divide(r2));
            System.out.println(r2 + " is " + r2.doubleValue());
        }
    }
    
    2 + 2/3 = 8/3
    2 - 2/3 = 4/3
    2 * 2/3 = 4/3
    2 / 2/3 = 3
    2/3 is 0.6666666666666666
    

    当使用+号将一个字符串和一个对象进行连接时,使用的是来自toString()方法的这个对象的字符串表示同这个字符串进行链接,所以,r1 + " + " + r2 + " = " + r1.add(r2)等价于r1.toString() + " + " + r2.toString() + " = " + r1.add(r2).toString()

    Write by Gqq

  • 相关阅读:
    HBase 文件读写过程描述
    Kafka 部署指南-好久没有更新博客了
    《Python高性能编程》——列表、元组、集合、字典特性及创建过程
    Ansible常用功能
    vim内替换文件内容
    线程队列-queue
    Python多进程
    python多线程知识-实用实例
    夜间模式的实现
    本地通知的实现
  • 原文地址:https://www.cnblogs.com/zgqcn/p/12820922.html
Copyright © 2020-2023  润新知