开发者

Java中的包、抽象类、接口详解(最新整理)

目录
    • 导入包
    • 静态导入
    • 将类放入包
    • 常见的系统包
  • 抽象类
    • 语法规则
    • 抽象类的作用
  • 接口
    • 语法规则
    • 实现多个接口
    • 接口间的继承
    •  (法一)实现Comparable接口的compareTo()方法
    • (法二)实现Comparator比较器的compare()方法
    • Clonable接口和深拷贝
  • 抽象类和接口的区别

    包 (package) 是组织类的一种方式, 使用包的主要目的是保证类的唯一性. 例如 , 你在代码中写了一个 Test 类 . 然后你的同事也可能写一个 Test 类 . 如果出现两个同名的类 , 就会冲突 , 导致代码不能编译通过.

    导入包

    Java 中http://www.devze.com已经提供了很多现成的类供我们使用 . 例如

    public class Test {
        public static void main(String[] args) {
            java.util.Date date = new java.util.Date();
            // 得到一个毫秒级别的时间戳
            System.out.println(date.getTime());
       }
    }

    可以使用 java.util.Date 这种方式引入 java.util 这个包中的 Date 类 . 但是这种写法比较麻烦一些 , 可以使用 import 语句导入包 . 如果需要使用 java.util 中的其他类 , 可以使用 import java.util.* 但是我们更建议显式的指定要导入的类名 . 否则还是容易出现冲突的情况

    注意事项 : import 和 C++ 的 #include 差别很大 . C++ 必须 #include 来引入其他文件内容 , 但是 Java 不需要 . import 只是为了写代码的时候更方便 . import 更类似于 C++ 的 namespace 和 using

    静态导入

    使用 import static 可以导入包中的静态的方法和字段。

    import static java.lang.System.*;
    public class Test {
        public static void main(String[] args) {
            out.println("hello");
       }
    }

     使用这种方式可以更方便的写一些代码, 例如

    import static java.lang.Math.*;
    public class Test {
        public static void main(String[] args) {
            double x = 30;
            double y = 40;
            // 静态导入的方式写起来更方便一些. 
            // double result = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
            double result = sqrt(pow(x, 2) + pow(y, 2));
            System.out.println(result);
       }
    }

    将类放入包

    基础规则

    在文件的最上方加上一个 package 语句指定该代码在哪个包中 . 包名需要尽量指定成唯一的名字 , 通常会用公司的域名的颠倒形式 ( 例如 com.bit.demo1 ). 包名要和代码路径相匹配 . 例如创建 com.bit.demo1 的包 , 那么会存在一个对应的路径 com/bit/demo1 来存储代码. 如果一个类没有 package 语句 , 则该类被放到一个默认包中 .

    常见的系统包

    1. java.lang: 系统常用基础类 (String 、 Object), 此包从 JDK1.1 后自动导入。

    2. java.lang.reflect:java 反射编程包 ;

    3. java.net: 进行网络编程开发包。

    4. java.sql: 进行数据库开发的支持包。

    5. java.util: 是 java 提供的工具程序包, ( 集合类等 )。 

    6. java.io:I/O 编程开发包。

    抽象类

    语法规则

    像这种没有实际工作的方法, 我们可以把它设计成一个 抽象方法 (abstract method) , 包含抽象方法的类我们称为 抽象类(abstract class)。

    abstract class Shape {
            abstract public void draw();
    }
    在 draw 方法前加上 abstract 关键字 , 表示这是一个抽象方法 . 同时抽象方法没有方法体 ( 没有 { }, 不能执行具体代码). 对于包含抽象方法的类 , 必须加上 abstract 关键字表示这是一个抽象类 .

    总结 

    1.抽象类是被abstract修饰的

    2.被abstract修饰的方法称为抽象方法,该方法可以没有具体的实现。

    3.当一个类中含有抽象方法的时候,该类必须使用abstract修饰

    4.抽象类当中可以有和普通类一样的成员变量和一样的成员方法

    5.抽象类是不可以被实例化的。

    6.抽象类既然不能实例化对象那么要抽象类干什么???就是为了被继承。

    7.当一个普通的类继承了这个抽象类之后,这个普通类一定要重写这个抽象类当中所有的抽象方法。

    8.final和abstract是不同同时存在的,抽象方法不能被private和static修饰!

    9.当一个抽象类A不想被一个普通类B继承,此时可以把B这个类变成抽象类,那么再当一个普通类C继承这个抽象类B之后,C要重写B和A里面所有的抽象方法。 

    注意事项:

    1) 抽象类不能直接实例化

    Shape shape = new Shape(); 
    // 编译出错
    Error:(30, 23) java: Shape是抽象的; 无法实例化

    2) 抽象方法不能是 private 的

    abstract class Shape { 
         abstract private void draw(); 
    } 
    // 编译出错
    Error:(4, 27) java: 非法的修饰符组合: abstract和private

    3) 抽象类中可以包含其他的非抽象方法 , 也可以包含字段 . 这个非抽象方法和普通方法的规则都是一样的 , 可以被重写 , 也可以被子类直接调用

    abstract class Shape { 
     abstract public void draw(); 
         void func() { 
         System.out.println("func"); 
     } 
    } 
    class Rect extends Shape { 
         ... 
    } 
    public class Test { 
     public static void main(String[] args) { 
         Shape shape = new Rect(); 
         shape.func(); 
     } 
    } 
    // 执行结果
    func

    4)抽象类不一定有抽象方法,但有抽象方法的类一定是抽象类。

    5)抽象类中可以有构造方法,供子类创建对象时,初始化父类的成员变量。

    抽象类的作用

    抽象类存在的最大意义就是为了被继承 . 抽象类本身不能被实例化 , 要想使用 , 只能创建该抽象类的子类 . 然后让子类重写抽象类中的抽象方法 .

    接口

    接口是抽象类的更进一步 . 抽象类中还可以包含非抽象方法 , 和字段 . 而接口中包含的方法都是抽象方法 , 字段只能包含静态常量。

    语法规则

    interface IShape { 
         void draw(); 
    } 
    class Cycle implements IShape { 
         @Override 
         public void draw() { 
             System.out.println("○"); 
         } 
    } 
    public class Test { 
         public static void main(String[] args) { 
             IShape shape = new Rect(); 
             shape.draw(); 
         } 
    }

    1.使用 interface 定义一个接口

    2.接口中的方法一定是抽象方法 , 因此可以省略 abstract

    3.接口中的方法一定是 public, 因此可以省略 public

    4.Cycle 使用 implements 继承接口 . 此时表达的含义不再是 " 扩展 ", 而是 " 实现 "

    5.在调用的时候同样可以创建一个接口的引用 , 对应到一个子类的实例 .

    6.接口不能单独被实例化

    接口中只能包含抽象方法. 对于字段来说, 接口中只能包含静态常量(final static).

    interface IShape { 
         void draw(); 
         public static final int num = 10; 
    }

     其中的 public, static, final 的关键字都可以省略. 省略后的 num 仍然表示 public 的静态常量。

    Java中的包、抽象类、接口详解(最新整理)

    总结

    1.使用interface来定义一个接口

    ⒉.接口当中的成员变量默认是public static final的,一般情况下我们不写

    3.接口当中的成员方法默认是public abstact ,一般情况下我们不写

    4.接口当中不可以有普通的方法。

    5.Java8开始允许在接口当中定义一个default方法,可以有具体的实现的

    6.接口当中的方法如果是static修饰的方法那么是可以有具体的实现的

    7.接口不能通过new关键字进行实例化。

    8.类和接口之间可以通过关键字implements来实现接口。

    9.接口也可以发生向上转型和动态绑定的。

    10.当一个类实现接口当中的方法之后,当前类当中的方法不能不加public

    11.接口当中不能有构造方法和代码块。

    12.一个接口也会产生独立的字节码文件。

    实现多个接口

    有的时候我们需要让一个类同时继承自多个父类. 这件事情在有些编程语言通过 多继承 的方式来实现的。然而 Java 中只支持单继承, 一个类只能 extends 一个父类. 但是可以同时实现多个接口, 也能达到多继承类似的效果.

    现在我们通过类来表示一组动物. 

    class Animal { 
         protected String name; 
         public Animal(String name) { 
             this.name = name; 
         } 
    }

    另外我们再提供一组接口 , 分别表示 " 会飞的 ", " 会跑的 ", " 会游泳的”。

    interface IFlying { 
         void fly(); 
    } 
    interface IRunning { 
         void run(); 
    } 
    interface ISwimming { 
         void swim(); 
    }

    接下来我们创建几个具体的动物 猫 , 是会跑的 .

    class Cat extends Animal implements IRunning { 
         public Cat(String name) { 
             super(name); 
         } 
         @Override 
         public void run() { 
             System.out.println(this.name + "正在用四条腿跑"); 
         } 
    }

    鱼 , 是会游的。

    class Fish extends Animal implements ISwimming { 
         public Fish(String name) { 
             super(name); 
         } 
         @Override 
         public void swim() { 
             System.out.println(this.name + "正在用尾巴游泳"); 
         } 
    }

    青蛙 , 既能跑 , 又能游 ( 两栖动物 )。

    class Frog extends Animal implements IRunning, ISwimming { 
         public Frog(String name) { 
             super(name); 
         } 
         @Override 
         public void run() { 
             System.out.println(this.name + "正在往前跳"); 
         } 
         @Override 
         public void swim() { 
             System.out.println(this.name + "正在蹬腿游泳"); 
         } 
    }

    还有一种神奇的动物 , 水陆空三栖 , 叫做 " 鸭子 "。

    class Duck extends Animal implements IRunning, ISwimming, IFlying {
        public Duck(String name) {
            super(name);
        }
        @Override
        public void fly() {
            System.out.println(this.name + "正在用翅膀飞");
        }
        @Override
        public void run() {
            System.out.println(this.name + "正在用两条腿跑");
        }
        @Override
        public void swim() {
            System.out.println(this.name + "正在漂在水上");
        }
    }

    上面的代码展示了 Java 面向对象编程中最常见的用法: 一个类继承一个父类, 同时实现多种接口.

    继承表达的含义是 is - a 语义, 而接口表达的含义是 具有 xxx 特性 .

    猫是一种动物, 具有会跑的特性.

    青蛙也是一种动物, 既能跑, 也能游泳

    鸭子也是一种动物, 既能跑, 也能游, 还能飞

    接口间的继承

    接口可以继承一个接口, 达到复用的效果. 使用 extends 关键字.

    interface IRunning {
        void run();
    }
    interface ISwimming {
        void swim();
    }
    // 两栖的动物, 既能跑, 也能游
    interface IAmphibious extends IRunning, ISwimming {
    }
    class Frog implements IAmphibious { 
     ...
    }

    通过接口继承创建一个新的接口 IAmphibious 表示 " 两栖的 ". 此时实现接口创建的 Frog 类 , 就继续要实现 run 方法 , 也需要实现 swim 方法 . 接口使用实例 给对象数组排序

    class Student{
        private String name;
        private int score;
        public Student(String name, int score) {
            this.name = name;
            this.score = score;
        }
        @Override
        public String toString() {
            return "[" + this.name + ":" + this.score + "]";
        }
    }
    public class test {
        public static void main(String[] args) {
            Student[] students = new Student[] {
                    new Student("张三", 95),
                    new Student("李四", 96),
                    new Student("王五", 97),
                    new Student("赵六", 92),
            };
            Arrays.sort(students);
            System.out.println(Arrays.toString(studphpents));
        }
    }

    运行会发现,抛异常了,原因是我们是对学生对象进行排序的,而非像整数这样显而易见能比大小的,因此我们需要实现Comparable接口,并实现其compareTo()方法。

    Java中的包、抽象类、接口详解(最新整理)

     (法一)实现Comparable接口的compareTo()方法

    class Student implements Comparable<Student>{
        private String name;
        private int score;
        public Student(String name, int score) {
            this.name = name;
            this.score = score;
        }
        @Override
        public String toString() {
            return "[" + this.name + ":" + this.score + "]";
        }
    //    @Override
    //    public int compareTo(Object o) {
    //        Student s=(Student)o;
    //        return this.score-s.score;
    //    }
        @Override
        public int compareTo(Student o) {
            return this.score-o.score;
        }
    }
    public class test {
        public static void main(String[] args) {
            Student[] students = new Student[] {
                    new Student("张三", 95),
                    new Student("李四", 96),
                    new Student("王五", 97),
                    new Student("赵六", 92),
            };
            Arrays.sort(students);
            System.out.println(Arrays.toString(students));
        }
    }

     运行结果

    Java中的包、抽象类、接口详解(最新整理)

    (法二)实现Comparator比较器的compare()方法

    class Student{
        public String name;
        public int score;
        public Student(String name, int score) {
            this.name = name;
            this.score = score;
        }
        @Override
        public String toString() {
            return "[" + this.name + ":" + this.score + "]";
        }
    }
    class AgeComparator implements Comparator<Student>{
        @Override
        public int compare(Student o1, Student o2) {
            return o1.score-o2.score;
        }
    }
    class NameComparator implements Comparator<Student>{
        @Override
        public int compare(Student o1, Student o2) {
            return o1.name.compareTo(o2.name);
        }
    }
    public class test {
        public static void main(String[] args) {
            Student student1 = new Student("zhangsan",10);
            Student student2 = new Student("lisi",15);
            AgeComparator ageComparator = new AgeComparator();
            System.out.println(ageComparator.compare(student1, student2));
            NameComparator nameComparator = new NameComparator();
            System.out.println(nameComparator.compare(student1,student2));
        }
    }

    运行结果

    Java中的包、抽象类、接口详解(最新整理)

    Clonable接口和深拷贝

    Java 编程客栈中内置了一些很有用的接口, Clonable 就是其中之一.

    Object 类中存在一个 clone 方法, 调用这个方法可以创建一个对象的 "拷贝". 但是要想合法调用 clone 方法, 必须要先实现 Clonable 接口, 否则就会抛出 CloneNotSupportedException 异常.

    class Money{
        public double money = 19.9;
    }
    class Person implements Cloneable{
        public int age;
        pjavascriptublic Money m;
        public Person(int age) {
            this.age = age;
            this.m = new Money();
        }
        @Override
        protected Object clone() throws CloneNotSupportedException {
            return super.clone();
        }
        @Override
        public String toString() {
            return "Person{" +
                    " age=" + age +
                    '}';
        }
    }
    public class Test2 {
        public static void main(String[] args) throws CloneNotSupportedException {
            Person person1 = new Person(10);
            Person person2 = (Person)person1.clone();
            System.out.println(person1.m.money);
            System.out.println(person2.m.money);
            System.out.println("==========================");
            person2.m.money = 99.99;
            System.pythonout.println(person1.m.money);
            System.out.println(person2.m.money);
        }
    }

    运行结果

    Java中的包、抽象类、接口详解(最新整理)

    与我们预期的19.9    99.99不符,显然是因为这里是浅拷贝,因此我们需要对m实现深拷贝。

    原因如下图:

    Java中的包、抽象类、接口详解(最新整理)

    实现深拷贝后

    class Money implements Cloneable{
        public double money = 19.9;
        @Override
        protected Object clone() throws CloneNotSupportedException {
            return super.clone();
        }
    }
    class Person implements Cloneable{
        public int age;
        public Money m;
        public Person(int age) {
            this.age = age;
            this.m = new Money();
        }
        @Override
        protected Object clone() throws CloneNotSupportedException {
            Person tmp = (Person) super.clone();
            tmp.m = (Money) this.m.clone();
            return tmp;
        }
        @Override
        public String toString() {
            return "Person{" +
                    " age=" + age +
                    '}';
        }
    }
    public class Test2 {
        public static void main(String[] args) throws CloneNotSupportedException {
            Person person1 = new Person(10);
            Person person2 = (Person)person1.clone();
            System.out.println(person1.m.money);
            System.out.println(person2.m.money);
            System.out.println("==========================");
            person2.m.money = 99.99;
            System.out.println(person1.m.money);
            System.out.println(person2.m.money);
        }
    }

    运行结果:

    Java中的包、抽象类、接口详解(最新整理)

    实现方法如下图:

    Java中的包、抽象类、接口详解(最新整理)

    抽象类和接口的区别

    核心区别: 抽象类中可以包含普通方法和普通字段, 这样的普通方法和字段可以被子类直接使用(不必重写), 而接口中不能包含普通方法, 子类必须重写所有的抽象方法.

    Java中的包、抽象类、接口详解(最新整理)

    到此这篇关于Java中的包、抽象类、接口详解的文章就介绍到这了,更多相关Java包 抽象类 接口内容请搜索编程客栈(www.devze.com)以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程客栈(www.devze.com)!

    0

    上一篇:

    下一篇:

    精彩评论

    暂无评论...
    验证码 换一张
    取 消

    最新开发

    开发排行榜