澳门新葡萄京官网注册 2

澳门新葡萄京官网注册Effective java笔记(二),所有对象的通用方法

本文由码农网 –
单劼原创翻译,转发请看清文末的转发需要,迎接参加大家的付费投稿计划!

Java—面向对象

Object类的具有非final方法(equals、hashCode、toString、clone、finalize)都要固守通用约定(general contract),不然别的依赖于那一个约定的类(HashMap,HashSet等)将无法平常干活。

咱俩都以往在POJO中重写过equals(卡塔尔,compareTo(卡塔尔(قطر‎和toString(卡塔尔(قطر‎方法。可是另有其它能形成职分分开的更好的方法并带给更轻易的代码。阅读那篇文章来一探究竟吧!

1.目标转型  

  1. 三个基类的援用类型变量能够“指向”其子类的靶子
  2. 叁个基类的引用不得以访谈其子类对象新扩张的积极分子。
  3. 能够行使引用变量instanceof类名来判定该引用型变量所针没有错对象是或不是归于此类或该类的子类
  4. 子类的目的能够看成基类的靶子来采纳称作向上转型(upcasting),反之称为向下转型(downcasting)
  5. 三个子类的目的能够进步造型为父类的门类。即定义父类型的援用能够本着子类的对象

  先看多少个例证:

public class Person {    String name;    char gender;    Person(String name,char gender){        this.name = name;        this.gender = gender;    }}  public class Student extends Person {    double score;    Student(String name,char gender,double score){        super(name,gender);  //调用父类有参构造        this.score = score;        super.name = "Tom";    }         public static void main(String[] args) {        Person p = new Student("Tom",'男',80);    //向上转型        p.score = 100;        //编译错误,Java编译器会根据引用的类型,而不是对象的类型来检查调用的方法是否匹配。
                             //向上转型即基类引用指向子类,基类引用可以指向子类的对象,但通过父类的引用只能访问父类所定义的成员,不能访问子类扩展的部分
    System.out.println(p instanceof Person);  //true
    System.out.println(p instanceof Student);  //true

    }}

8、覆盖equals时请据守通用约定

无须覆盖equals的情形:

  • 类的每一个实例本质上是唯一的。类代表的是运动实体并非值的概念。(举个例子,类Thread
  • 不爱抚类“逻辑相等”的功能,从Object继承的equals落到实处已经足足。(举个例子,类Random
  • 超类的equals金玉满堂也适用于子类。(比如,ListAbstractList继承equals实现)
  • 类是private或包级私有(默许)的,能够鲜明它的equals办法长久不会被调用。
  • “每一种值最多有三个实例”的类,逻辑相同与对象相像雷同。(举例,枚举类,Singleton类)

亟待覆盖equals的情形:

  • 类具备“逻辑相等”的概念,并且超类未有隐讳equals方法。

覆盖equals时必得遵循的预定:

  • 自反性,x非空时,x.equals(x)返回true
  • 对称性,x, y非空时,若x.equals(y)返回true,则y.equals(x)返回true
  • 传递性,x, y, z非空时,若x.equals(y)返回truey.equals(z)返回true,则x.equals(z)返回true
  • 一致性,x, y非空时,多次调用x.equals(y)再次来到值一致
  • x非空时,x.equals(null)确定重回false

违反规定的例子:

在java类库中,java.sql.Timestamp继承自java.util.Date,并扩充了nanoseconds域。但Timestampequals达成违反了对称性(date.equals(timestamp) != timestamp.equals(date)),如果TimestampDate对象被混合在一同行使,将唤起不科学的行为。

澳门新葡萄京官网注册 1

Date的存在延续布局

equals贯彻代码:

    //Date中equals实现
    public boolean equals(Object obj) {
        return obj instanceof Date && getTime() == ((Date) obj).getTime();
    }

    //Timestamp中equals实现
    /* 
     * Note: This method is not symmetric with respect to the
     * equals(Object) method in the base class.
     */
    public boolean equals(java.lang.Object ts) {
      if (ts instanceof Timestamp) {
        return this.equals((Timestamp)ts);
      } else {
        return false;
      }
    }

注:在equals实现中,对于obj instanceof Date言辞,若obj为null,其将回到false。因而把null传个equals方法,无需举行独立的品种检查(决断obj是还是不是为null卡塔尔(قطر‎。

若将方面Timestampequals代码改为如下情势:

    //Timestamp改进的equals实现
    public boolean equals(java.lang.Object ts) {
      if (ts instanceof Timestamp) {
        return this.equals((Timestamp)ts);
      } else if (ts instanceof Date){
        return ((Date)ts).equals(this);
      } else {
        return false;
      }
    }

与此相类似确实保险了对称性,但却就义了Timestamp类的风味。

提姆estamp是Date 类的瘦包装器 (thin wrapperState of Qatar,它同意 JDBC API
将该类标志为 SQL TIMESTAMP 值。它丰盛保存 SQL TIMESTAMP
毫飞秒值和提供支撑时间戳值的 JDBC 转义语法的格式化和解析操作的本事。

落到实处equals方法的门道:

  • 使用 == 检查“参数是或不是为那一个指标的援用”,非常是相比操作相比昂贵时。

  • 行使instanceof操作符检查“参数是不是为不易的档期的顺序”,若不是回去false

  • 自己商酌参数中的域是不是与目的中的对应域相匹配

  • 编制完equals方法后检核对称性、传递性、一致性

注意:

  • 覆盖equals时总要覆盖hashCode

  • 无须将equals中的Object替换为此外体系,使用@Override public boolean equals(Object o),参数类型为Object,不然将重载equals方法

更明了的天职——抽身equals、compareTo和toString方法

你已经查看过java文书档案中的Object类吗?可能吧。每当你前行追溯世襲树的时候都会止步于这几个类。你会注意到,该类有多少个措施是每五个类都必得接二连三的。而你最欣赏重写的点子大概正是toString().equals() and .hashCode() 那八个了。(至于缘何总是应该并且重写后八个章程,请看Per-Åke
Minborg写的那篇文章:

不过仅唯有那一个点子显然是远远不够的。许几人将规范库中的其他的接口如Comparable和Serializable加以组合。可是那样实在明智吗?为啥各种人都很急迫地去团结落成那个艺术吧?事实上,当您希图将对象存款和储蓄在部分器皿中,如HashMap,何况想要控制哈希冲突的时候,完结您协调的.equals(卡塔尔(قطر‎方法和.hashCode(卡塔尔国方法真的有它的意义,但实现compareTo(State of Qatar和toString(卡塔尔国方法又是干吗呢?

本篇文章中自身将建议一种选择到Speedment
开源项目上的软件设计方法,这里的靶子的点子被定义为存款和储蓄于变量上的主意引用,实际不是重写它们。那样做确有一点点功利:你的POJO将会越来越短小简洁,通用的章程能够不须求持续而开展复用并且你能够因势利导地选取它们。

2.Object类 

  Object类坐落于java.lang包中,java.lang马鞍包含着Java最底子和中坚的类,在编写翻译时会自动导入;

  Object类是怀有Java类的祖宗。各样类都使用 Object
作为超类。全数指标都落到实处这些类的不二诀要。能够运用途目为Object的变量指向自便等级次序的对象

Object类是具备java类的根基类

只要在类的宣示中未使用extends关键字致命其基类,则默许基类为Object类,也便是说

public class Person {…}等价于public classPerson extends Object {…}

  Object类提供的不二等秘书诀: 

  • protected Object clone()
  • boolean equals(Object obj)
  • protected void finalize()
  • Class< > getClass()
  • int hashCode()
  • void notify()
  • void notifyAll()
  • String toString()
  • void wait()
  • void wait(long timeout)
  • void wait(long timeout, int nanos)

  java的别样类都世袭了那个函数,况且可以覆盖不被final修饰的函数。比方,未有final修饰的toString()函数可以被遮住,不过final wait()函数就极度。首要用的方式有toString和equals方法

9、覆盖equals时总要覆盖hashCode

每一种覆盖了equals方法的类中,必需覆盖hashCode方法,不然该类无法用于基于散列表的集结(HashMap,HashSet和HashTable)

对hashCode的约定:

  • 对同二个对象调用数十次(用于相比操作的新闻未被修正),hashCode重临同一个莫西干发型

  • equals相比较相等,则hashCode重回的值必需一律

  • equals比较不对等,hashCode重回的值大概相似,也只怕分裂

分外的目的必需有所极其的hashCode值;hashCode值分化,对象自然不对等,为不等于的目的发生不对等的散列码能够巩固散列表的习性。散列函数应该把不等于的实例均匀分配到具备极大希望的散列值上。

一种总计散列码的方法:

1、保存二个非零的常数值,result = 17

2、为指标中各种域f(equals方法中关系的域)总括int型的散列码c

  • 域为boolean类型,c = f ? 1 : 0
  • 域为byte,char,short或int类型,c = (int) f
  • 域为long类型,c = (int)(f^(f >>> 32))
  • 域为float类型,c = Float.floatToIntBits(f)
  • 域为double类型,f = Double.doubleToLongBits(f); c = (int)(f^(f >>> 32))
  • 域为一个对象的引用,c = f.hashCode()
  • 域为数组,利用此格局递合併括数组的hashCode值

3、将享有的散列码合併到result,递归调用result = result * 31 + c

例如:

    @Override
    public int hashCode() {
        int result = 17;
        result = 31 * result + fa;
        result = 31 * result + fb;
        result = 31 * result + fc;
        return result;
    }

使用31的原因:

31是三个奇素数况兼31足以采用移动和减法来取代乘法以抓牢品质,如:31 * i == (i << 5) - i。今世的JVM能够自动达成这种优化

对于不可变类,若每便总结hashCode的支出十分的大,可将散列码缓存在对象内部,实际不是历次央求时都再次总括散列码。如:

    private volatile int hashCode = 0; //volatile

    @Override
    public int hashCode() {
        if (hashCode != 0) {
            return hashCode;
        }
        int result = 17;
        result = 31 * result + fa;
        result = 31 * result + fb;
        result = 31 * result + fc;
        hashCode = result;
        return result;
    }

本来的代码

先是大家来看下边的代码:这里有八个超人的Java类Person。在应用中供给从五个Set中打字与印刷出每一个person对象,何况依据姓在前和名在后的顺序排列(以免现身四个一律姓氏的人)。

Person.java

public class Person implements Comparable<Person> {
    private final String firstname;
    private final String lastname;
    public Person(String firstname, String lastname) {
        this.firstname = firstname;
        this.lastname  = lastname;
    }
    public String getFirstname() {
        return firstname;
    }
    public String getLastname() {
        return lastname;
    }
    @Override
    public int hashCode() {
        int hash = 7;
        hash = 83 * hash + Objects.hashCode(this.firstname);
        hash = 83 * hash + Objects.hashCode(this.lastname);
        return hash;
    }
    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true;
        if (obj == null) return false;
        if (getClass() != obj.getClass()) return false;
        final Person other = (Person) obj;
        if (!Objects.equals(this.firstname, other.firstname)) {
            return false;
        }
        return Objects.equals(this.lastname, other.lastname);
    }
    @Override
    public int compareTo(Person that) {
        if (this == that) return 0;
        else if (that == null) return 1;
        int comparison = this.firstname.compareTo(that.firstname);
        if (comparison != 0) return comparison;
        comparison = this.lastname.compareTo(that.lastname);
        return comparison;
    }
    @Override
    public String toString() {
        return firstname + " " + lastname;
    }
}

Main.java

public class Main {
    public static void main(String... args) {
        final Set
      people = new HashSet<>();
        people.add(new Person("Adam", "Johnsson"));
        people.add(new Person("Adam", "Samuelsson"));
        people.add(new Person("Ben", "Carlsson"));
        people.add(new Person("Ben", "Carlsson"));
        people.add(new Person("Cecilia", "Adams"));
        people.stream()
            .sorted()
            .forEachOrdered(System.out::println);
    }
}

Output

run:
Adam Johnsson
Adam Samuelsson
Ben Carlsson
Cecilia Adams
BUILD SUCCESSFUL (total time: 0 seconds)

Person 类达成了部分方法来支配输出。 hashCode()equals() 方法确认保障同八个person对象不会被重复增加到set中。.compareTo() 方法用于排序方法中生成应有的逐一。而重写方法toString()是在System.out.println() 被调用的时候决定各种Person对象的出口格式。你认出这种构造了吗?大约任何贰个java工程中都会有它。

  1.toString方法    

  • Object类中定义有public String
    toString(卡塔尔国方法,其重临值是String类型,描述当前指标的关于音讯
  • 在进展String与别的品种数据的链接操作时(如:System.out.print(“info”+person卡塔尔),将活动调用该对象类的toString(State of Qatar方法
  • 能够依据要求在客商自定义类型中重写toString(State of Qatar方法

    //测试类public class Test {    public static void main(String[] args) {        Dog d = new Dog();        System.out.println("d: "+d);        //等价于         System.out.println("d: "+d.toString;    }}class Dog {    }//输出结果://d: test.Dog@2a139a55//d: test.Dog@2a139a55
    

    输出的结果就是类的目的的相干新闻  

   借使对于Object中或多或少方法不及意能够自个儿在团结类中张开重写,比方:

public class Test {    public static void main(String[] args) {        Dog d = new Dog();        System.out.println("d: "+d);        //等价于        System.out.println("d: "+d.toString;    }}class Dog {        public String toString(){        return "Dog";    }}//输出结果d: Dogd: Dog

10、始终要隐瞒toString

toString的预订,提议全部的类都完毕toString方法。toString完结能够使类用起来更为酣畅,有助于调节和测验时音信的确诊。

假诺指标太大或新闻难以用字符串描述,应该回到三个摘要音信。在文书档案中注明toString的回到格式。

代替这一个代码

对待于将全体那个形式写入Person类中,我们得以让它保持尽量的精短,使用办法援用去管理它们。大家得以去除全部equals(卡塔尔(قطر‎,hashCode(卡塔尔(قطر‎,compareTo(卡塔尔(قطر‎和toString(State of Qatar的样本式代码,取而代之的是下面介绍的多少个静态变量:COMPARATOR 和TO_STRING

Person.java

public class Person {
    private final String firstname;
    private final String lastname;
    public Person(String firstname, String lastname) {
        this.firstname = firstname;
        this.lastname  = lastname;
    }
    public String getFirstname() {
        return firstname;
    }
    public String getLastname() {
        return lastname;
    }
    public final static Comparator<Person> COMPARATOR =
        Comparator.comparing(Person::getFirstname)
            .thenComparing(Person::getLastname);
    public final static Function<Person, String> TO_STRING =
        p -> p.getFirstname() + " " + p.getLastname();
}

Main.java

public class Main {
    public static void main(String... args) {
        final Set
      people = new TreeSet<>(Person.COMPARATOR);
        people.add(new Person("Adam", "Johnsson"));
        people.add(new Person("Adam", "Samuelsson"));
        people.add(new Person("Ben", "Carlsson"));
        people.add(new Person("Ben", "Carlsson"));
        people.add(new Person("Cecilia", "Adams"));
        people.stream()
            .map(Person.TO_STRING)
            .forEachOrdered(System.out::println);
    }
}

Output

run:
Adam Johnsson
Adam Samuelsson
Ben Carlsson
Cecilia Adams
BUILD SUCCESSFUL (total time: 0 seconds)

那样完成的利润是大家得以在毫不校订Person类的动静下替换排序战术或打字与印刷格式。那将使代码具备越来越强的可维护性和复用性,更毫不说更加快的编写制定速度了。

  2.equals方法

    Object类中定义了public boolean
equals(Object obj卡塔尔方法

    提供定义对象是还是不是等于的逻辑(比较的是在堆内部存款和储蓄器中的内部存款和储蓄器地址),使用格式:

x.equals当x和y是同叁个对象的利用时重返true,斗则赶回false

    注意:jdk提供的部分类,如String,Date等,重写了Object的equals方法,调用这几个类的equals方法,x.equals,当x和y所引述的指标是平等类对象且属性值相等时(并不一定是大同小异对象),再次来到true,不然再次来到false
(重写了Object的equals方法的包装,例如String类对象,他们使用equals方法比较的正是属性值即成员变量的值)

    能够依照需求在客户自定义类型中重写equals方法

public class Test {    public static void main(String[] args) {        Dog d1 = new Dog();        Dog d2 = new Dog();                System.out.println(d1 == d2);        System.out.println(d1.equals;            }}class Dog {    }//输出结果://false//false

public class Test {    public static void main(String[] args) {        Dog d1 = new Dog();        Dog d2 = new Dog();                System.out.println(d1 == d2);        System.out.println(d1.equals;            }}class Dog {        public boolean equals(Object obj) {        return true;    }}//输出结果://false//true

    从上边多少个例子能够看出系统方法也是足以重写的,相同的时候能够看见“==”那些运算符,要是是援引类型相比的正是堆内部存款和储蓄器中的内部存款和储蓄器地址,假如是基本数据类型相比较的是值(基本数据类型的有些变量贮存在栈中),成立出来的对象的成员变量寄存在堆内部存款和储蓄器的常量池中  

11、谨严的覆盖clone

一个类完结了Cloneable接口,表名那些类允许被克隆。Cloneable接口是个空切口,仅仅用来标识那么些类能够被复制,具体落实将由JVM调用Object中的原生方法clone(卡塔尔实现。所以二个类要能够复制必需兑现Cloneable接口一碗水端平写clone(卡塔尔国方法。

至于clone方法的贯彻参见博客java中clone方法的兑现

  3.hashCode方法   

    public``native``int``hashCode();

    hash值:Java中的hashCode方法就是基于早晚的准则将与对象相关的消息(比方对象的仓库储存地方,对象的字段等)映射成三个数值,那个数值称作为散列值。

    情景:考虑一种情状,当向聚聚集插入对象时,怎样识别在集结中是不是早就存在该目的了?(注意:集结中不容许再次的要素存在)。

    大超级多人都会想到调用equals方法来各个拓宽相比,那个格局真的管用。可是只要集结中已经存在一万条数据恐怕越多的多寡,倘若接收equals方法去各样相比较,功能必然是三个标题。当时hashCode方法的功效就反映出来了,当会集要增加新的靶猴时,先调用这些指标的hashCode方法,获得相应的hashcode值。实际上在HashMap的现实贯彻中会用七个table保存已经存进去的靶子的hashcode值,借使table中向来不应当hashcode值,它就足以一直存进去,不用再开展任何相比了;要是存在该hashcode值,
就调用它的equals方法与新成分进行比较,相像的话就不存了,不等同就散列别的的地点。

    重写hashCode()方法的骨干准绳:

    1. 在程序运营进度中,同一个指标往往调用hashCode()方法应该回到肖似的值。
    2. 当三个目的通过equals()方法比较重回true时,则三个对象的hashCode()方法重临相等的值。
    3. 对象用作equals()方法相比标准的Field,都应当用来计量hashCode值。

Object本地实现的hashCode(卡塔尔(قطر‎方法计算的值是底层代码的得以完成,选取各个划算参数,重临的并不一定是目的的内部存款和储蓄器地址,具体决意于运维时库和JVM的实际达成。

public boolean equals(Object obj) {       return (this == obj);} 

12、考虑达成Comparable接口

兑现了Comparable接口的类,注解它的实例具备内在的排序关系,能够使用Arrays.sort(comp)主意对其数组举办排序。一旦类达成了Comparable接口,它就足以与众多泛型算法及正视于该接口的集合完成进行合营。若编写的类是有立场坚定的内在排序关系,那么就相应完毕Comparable接口。达成Comparable接口必须重写compareTo方法。

依附于相比较关系(compareTo方法)的类包含稳步会集类TreeSet和TreeMap,以至工具类Collection和Arrays,它们之中含有有追寻和排序算法。

compareTo方法的约定:

  • 该目的小于、等于、大于钦赐对象时,分别重返负整数、零、正整数。若两指标不一致,则抛出ClassCastException异常
  • x.compareTo(y) == 0x.equals(y)建议保持一致。

3.动态绑定

  Java的动态绑定又称为运转时绑定。动态绑定是指“在奉行时期剖断所引用对象的实际上类型,依照其实际的花色调用其相应的办法”

//新建一个基类public class Animal {    public String name;    Animal(String name) {        this.name = name;    }    public void eat() {        System.out.println("吃....");    }}

//新建一个子类Cat继承Animal基类public class Cat extends Animal {    Cat {        super;    }    public void eat() {        System.out.println("猫吃鱼...");    }}

//新建一个子类Dog继承基类Animalpublic class Dog extends Animal{    Dog {        super;    }    public void eat() {        System.out.println("狗吃屎...");    }}

//测试类public class Test {    public static void main(String args[]) {        Animal c = new Cat("catname");        Animal d = new Dog("dogname");        c.eat();        d.eat();    }}//输出结果://猫吃鱼.....//狗吃屎.....

  下边包车型大巴例证中,依照Animal对象的援引的不等的实际上类型而调用相应的eat方法  

  Animal c = new Cat(“catname”);

  Animal d = new Dog(“dogname”);

  上边两行代码的内部存款和储蓄器分配图如下:

    澳门新葡萄京官网注册 2    

    eat方法有八个,分别是animal的,dog的和cat的,动态绑定正是调用的实际new的百般格局,指向的就是万分情势。相当于c指向的骨子里方法应该是cat类重写的那多少个eat方法。在地点的对象转型中大家也讲过父类援用指向子类,可是不可能访谈子类新添成员,子类中重写父类方法规父类方法被遮住,调用的就是被重写后的主意

    当末世须要扩张的时候,只需求加四个恢宏类,然后在test类中new贰个扩展对象出来并选取对象.方法的法子援引就能够,扩充性极其强

  动态绑定有八个要求条件:1.要有世袭 2.要有重写 3.父类引用指向子类对象

4.抽象类和final关键字

  1.抽象类   

    1.运用abstract关键字来修饰二个类的时候,这几个类叫做抽象类;相似的,使用abstract来修饰八个办法时,那几个法子叫做抽象方法。

    2.含有抽象方法的类必需被声称为抽象类,抽象类必需被接续,抽象方法必得被重写。

    3.抽象类不可能被实例化,通过接二连三,然后向上转型来援用

    4.抽象方法只需评释,而不须要实现

    5.浮泛方法必需为public也许protected(因为只要为private,则不可能被子类世袭,子类便力所不比落到实处该方法),缺省景色下默以为public;

  看下边那几个事例:

abstract class A{//定义一个抽象类    public void fun(){//普通方法        System.out.println("存在方法体的方法");    }    public abstract void print();//抽象方法,没有方法体,有abstract关键字做修饰,方法只需要被声明不需要实现,因为抽象方法必须被重写,所以没必要实现抽象方法}  

public class B extends A{    public static void main(String[] args){        A a = new B(); //向上转型,父类引用指向子类        a.print();    }    public void print(){        System.out.println("子类重写父类的抽象方法");    }}//输出结果://子类重写父类的抽象方法

  2.final关键字

    final修饰的变量的值不可见被退换

    final修饰的不二秘诀不可以见到被重写

    final修饰的类不可能被一而再三番五次

public class Demo {    public static void main(String[] args) {        T t = new T();        t.i = 9;      //编译出错,因为变量i被final修饰,不能被修改值        t.j = 10;   //不会报错,因为变量j没有被final修饰    }    }class T {    final int i = 0;    int j = 0;}

5.Java接口

  接口(克罗地亚语:Interface),在JAVA编制程序语言中是叁个虚无类型,是抽象方法和常量值的定义的联谊,接口平常以interface来声称。三个类经过三回九转接口的不二法门,进而来继世襲口的抽象方法。

  接口并非类,编写接口的秘诀和类很平日,不过它们归于差别的定义。类描述对象的天性和办法。接口则带有类要落到实处的艺术。本质上讲,接口是一种独特的抽象类,这种抽象类中值满含常量和艺术的定义,而未有变量和方式的兑现

  除非完成接口的类是抽象类,不然该类要定义接口中的全数办法。

  接口无法被实例化,可是足以被完结。多个完毕接口的类,必需兑现接口内所描述的富有办法,不然就亟须表明为抽象类。其它,在
Java
中,接口类型可用来声称多少个变量,他们能够改为一个空指针,或是被绑定在三个以此接口完毕的对象。  

  接口定义比方:

public interface Runner {    public static final int id = 1;    public void start();    public void run();    public void stop();}  

  接口天性:

  • 接口能够多种落到实处
  • 接口中宣示的属性默以为public static final的;也只可以是public static
    final的
  • 接口只好定义抽象方法,况且那些方法默以为public的,也必须要是public的
  • 接口能够持续别的的接口,并加多新的性质和抽象方法
  • 多少个非亲非故的类可以达成同三个接口
  • 叁个类能够兑现几个无关的接口
  • 与后续关系近乎,接口与完成类之间存在多态性

  定义java类的语法格式:

< modifier > class < name > [ extends < superclass > ] [ implements < interface > [ , <interface> ] * ] {     < declarations > * }

  示例:

interface Singger{    public void sing();} class Test implements Singger{//实现Singger接口    public static void main(String[] args){        Test t = new Test();        t.sing();    }    public void sing() {        System.out.println("student is singing...");    }}//输出结果://student is singing...

发表评论

电子邮件地址不会被公开。 必填项已用*标注