Home  >  Article  >  Java  >  Detailed explanation of Java overloading, rewriting, and constructors

Detailed explanation of Java overloading, rewriting, and constructors

巴扎黑
巴扎黑Original
2017-09-21 11:58:181898browse

This article mainly introduces relevant information about Java overloading, rewriting, and detailed examples of constructor functions. I hope that through this article, everyone can understand and master the Java object-oriented method. Friends in need can refer to it

Java Detailed Examples of Overloading, Overriding, and Constructor

Method Rewriting

1. Rewriting can only appear in within the inheritance relationship. When a class inherits a method from its parent class, it has the opportunity to override the parent class's method. A special case is when a parent class method is marked final. The main advantage of overriding is the ability to define behavior specific to a subtype.


class Animal {
    public void eat(){
      System.out.println ("Animal is eating.");
    }
  }

  class Horse extends Animal{
    public void eat(){
      System.out.println ("Horse is eating.");
    }
  }

2. For abstract methods inherited from the parent class, either design the method by overriding it in the subclass, or mark the subclass as abstract . So abstract methods can be said to be methods that must be rewritten.

3. The meaning of rewriting.

Overriding methods can achieve polymorphism and use references from the parent class to manipulate subclass objects, but in actual operation the object will run its own unique method.


public class Test {
    public static void main (String[] args) {
      Animal h = new Horse();
      h.eat(); 
    }
  }

  class Animal {
    public void eat(){
      System.out.println ("Animal is eating.");
    }
  }

  class Horse extends Animal{
    public void eat(){
      System.out.println ("Horse is eating.");
    }
    public void buck(){
    }
  }

One principle is: whatever reference is used, the compiler will only call the methods owned by the reference class. If you call a subclass-specific method, such as h.buck() in the above example; the compiler will complain (compilation error). That is, the compiler only looks at reference types, not object types.

4. Rules for overriding methods.

If you want to implement a qualified rewriting method instead of overloading, you must meet the following requirements at the same time!

A. One of the rewriting rules: the overriding method cannot have a more restrictive access level than the overridden method.
(But it can be broader. For example, the parent class method has package access rights, and the overridden method of the subclass has public access rights.)
For example: the Object class has a toString() method, start overriding this method Sometimes we tend to forget the public modifier, and the compiler will certainly not miss any opportunity to teach us a lesson. The reason for the error is that methods without any access modifiers have package access rights. Package access rights are of course stricter than public, so the compiler will report an error.

B. Rewriting Rule 2: The parameter list must be the same as that of the overridden method.

Rewrite has a twin brother called Overload, who will appear later. If the parameters of the subclass method are different from the corresponding method of the parent class, then you have got the wrong person. That is overloading, not overriding.

C. Rewriting rule three: **The return type must be the same as the return type of the overridden method.

Parent class method A: void eat(){} Subclass method B: int eat(){} Although the parameters are the same, the return types are different, so they are not rewritten. **

Parent class method A: int eat(){} Subclass method B: long eat(){} Although the return type is compatible with the parent class, the difference is different, so it is not an override.

D. Overriding Rule 4: The overriding method cannot throw a new exception or a wider checked exception than the checked exception declared by the overridden method. But it is possible to throw fewer, more limited, or no exceptions.


import java.io.*;
  /**
  * Java学习交流QQ群:589809992 我们一起学Java!
  */
  public class Test {
    public static void main (String[] args) {
      Animal h = new Horse();
      try {
        h.eat(); 
      }
      catch (Exception e) {
      }
    }
  }

  class Animal {
    public void eat() throws Exception{
      System.out.println ("Animal is eating.");
      throw new Exception();
    }
  }

  class Horse extends Animal{
    public void eat() throws IOException{
      System.out.println ("Horse is eating.");
      throw new IOException();
    }
  }

In this example, the parent class throws a checked exception Exception, and the IOException thrown by the subclass is a subclass of Exception, that is, the overridden method A more limited exception is thrown, which is OK. If, on the other hand, the parent class throws IOException and the subclass throws a broader Exception, it will not be compiled.
Note: This restriction is only for checked exceptions. Runtime exception RuntimeException and its subclasses are no longer subject to this restriction.

E. Rewriting Rule 5: Methods marked as final cannot be overridden.

F. Rewriting Rule 6: If a method cannot be inherited, it cannot be overridden.

The more typical one is the private method of the parent class. The following example produces an interesting phenomenon.


public class Test {
    public static void main (String[] args) {
      //Animal h = new Horse();
      Horse h = new Horse();
      h.eat();
    }
  }

  class Animal {
    private void eat(){
      System.out.println ("Animal is eating.");
    }
  }

  class Horse extends Animal{
    public void eat(){
      System.out.println ("Horse is eating.");
    }
  }

This code can be compiled. On the surface it seems like a violation of Rule 6, but in reality it was a bit of a coincidence. The eat() method of the Animal class cannot be inherited, so the eat() method in the Horse class is a brand new method, not a rewrite or an overload, but a brand new method that only belongs to the Horse class! This confuses many people, but it is not that difficult to understand.

If the main() method is like this:


  Animal h = new Horse();
  //Horse h = new Horse();
  h.eat();

The compiler will report an error, why? The eat() method of the Horse class is public! It should be able to be called! Please keep in mind that polymorphism only looks at the methods referenced by the parent class, not the methods of the subclass object!

Overloading of methods

Overloading is friendly, it does not require you to convert the data type before calling a method, it will automatically find a match Methods. Method overloading determines which method to call at compile time, which is different from overriding. The most commonly used place is the overloading of the constructor.

1. Overloading of basic data type parameters.


/**
 * Java学习交流QQ群:589809992 我们一起学Java!
 */
public class Test {
    static void method(byte b){
      System.out.println ("method:byte");
    }
    static void method(short s){
      System.out.println ("method:short");
    }
    static void method(int i){
      System.out.println ("method:int");
    }
    static void method(float f){
      System.out.println ("method:float");
    }
    static void method(double d){
      System.out.println ("method:double");
    }
    public static void main (String[] args) {
      method((byte)1);
      method('c');
      method(1);
      method(1L);
      method(1.1);
      method(1.1f);
    }
  }

Output result:


method:byte
method:int
method:int
method:float
method:double
method:float

  可以看出:首先要寻找的是数据类型正好匹配方法。如果找不到,那么就提升为表达能力更强的数据类型,如上例没有正好容纳long的整数类型,那么就转换为 float类型的。如果通过提升也不能找到合适的兼容类型,那么编译器就会报错。反正是不会自动转换为较小的数据类型的,必须自己强制转换,自己来承担转变后果。

  char类型比较特殊,如果找不到正好匹配的类型,它会转化为int而不是short,虽然char是16位的。

2、重载方法的规则。

A、被重载的方法必须改变参数列表。

参数必须不同,这是最重要的!不同有两个方面,参数的个数,参数的类型,参数的顺序。

B、被重载的方法与返回类型无关。

也就是说,不能通过返回类型来区分重载方法。

C、被重载的方法可以改变访问修饰符。

没有重写方法那样严格的限制。

D、被重载的方法可以声明新的或者更广的检查异常。

没有重写方法那样严格的限制。

E、方法能够在一个类中或者在一个子类中被重载。

3、带对象引用参数的方法重载。


class Animal {}
  class Horse extends Animal{}

  public class Test {
    static void method(Animal a){
      System.out.println ("Animal is called.");
    }
    static void method(Horse h){
      System.out.println ("Horse is called.");
    }
    public static void main (String[] args) {
      Animal a = new Animal();
      Horse h = new Horse();
      Animal ah = new Horse();

      method(a);
      method(h);
      method(ah);
    }
  }

输出结果是:


Animal is called.
Horse is called.
Animal is called.

前两个输出没有任何问题。第三个方法为什么不是输出“Horse is called.”呢?还是那句老话,要看引用类型而不是对象类型,方法重载是在编译时刻就决定的了,引用类型决定了调用哪个版本的重载方法。

4、重载和重写方法区别的小结。

如果能彻底弄明白下面的例子,说明你对重载和重写非常了解了,可以结束这节的复习了。


class Animal {
    public void eat(){
      System.out.println ("Animal is eating."); 
    }
  }
  class Horse extends Animal{
    public void eat(){
      System.out.println ("Horse is eating."); 
    }
    public void eat(String food){
      System.out.println ("Horse is eating " + food);
    }
  }

  public class Test {
    public static void main (String[] args) {
      Animal a = new Animal();
      Horse h = new Horse();
      Animal ah = new Horse();

      a.eat();
      h.eat();
      h.eat("apple");
      ah.eat();
      //a.eat("apple");
      //ah.eat("apple");
    }
  }

四个输出分别是什么?被注释的两条语句为什么不能通过编译?

第一条:a.eat(); 普通的方法调用,没有多态,没什么技术含量。调用了Animal类的eat()方法,输出:Animal is eating.
第二条:h.eat(); 普通的方法调用,也没什么技术含量。调用了Horse类的eat()方法,输出:Horse is eating.
第三条:h.eat(“apple”); 重载。Horse类的两个eat()方法重载。调用了Horse类的eat(String food)方法,输出:Horse is eating apple
第四条:ah.eat(); 多态。前面有例子了,不难理解。输出:Horse is eating.
第五条:a.eat(“apple”); 低级的错误,Animal类中没有eat(String food)方法。因此不能通过编译。
第六条:ah.eat(“apple”); 关键点就在这里。解决的方法还是那句老话,不能看对象类型,要看引用类型。Animal类中没有eat(String food)方法。因此不能通过编译。

小结一下:多态不决定调用哪个重载版本;多态只有在决定哪个重写版本时才起作用。

重载对应编译时,重写对应运行时。够简洁的了吧!

构造方法

构造方法是一种特殊的方法,没有构造方法就不能创建一个新对象。实际上,不仅要调用对象实际类型的构造方法,还要调用其父类的构造方法,向上追溯,直到 Object类。构造方法不必显式地调用,当使用new关键字时,相应的构造方法会自动被调用。

1、构造方法的规则。

A、构造方法能使用任何访问修饰符。包括private,事实上java类库有很多都是这样的,设计者不希望使用者创建该类的对象。

B、构造方法的名称必须与类名相同。这样使得构造方法与众不同,如果我们遵守sun的编码规范,似乎只有构造方法的首字母是大写的。

C、构造方法不能有返回类型。

反过来说,有返回类型的不是构造方法


  public class Test {
    int Test(){
      return 1;
    }
  }

这个方法是什么东西?一个冒充李逵的李鬼而已,int Test()和其他任何普通方法没什么两样,就是普通的方法!只不过看起来很恶心,类似恶心的东西在考试卷子里比较多。

D、如果不在类中创建自己的构造方法,编译器会自动生成默认的不带参数的构造函数。

这点很容易验证!写一个这样简单的类,编译。


class Test {
}

对生成的Test.class文件反编译:javap Test,可以看到:


D:"JavaCode"bin>javap Test
Compiled from "Test.java"
class Test extends java.lang.Object{
  Test();
}

看到编译器自动添加的默认构造函数了吧!

E、如果只创建了带参数的构造方法,那么编译器不会自动添加无参的构造方法的!

F、在每个构造方法中,如果使用了重载构造函数this()方法,或者父类的构造方法super()方法,那么this()方法或者super()方法必须放在第一行。而且这两个方法只能选择一个,因此它们之间没有顺序问题。

G、除了编译器生成的构造方法,而且没有显式地调用super()方法,那么编译器会插入一个super()无参调用。

H、抽象类有构造方法。

静态方法的重载与重写(覆盖)

1、静态方法是不能被覆盖的。可以分两种情况讨论:

A、子类的非静态方法“覆盖”父类的静态方法。

这种情况下,是不能通过编译的。


class Father{
   static void print(){
     System.out.println ( " in father  method " );
   }
}
class Child extends Father{
   void print(){
     System.out.println ( " in child method " );
   }
}

static方法表示该方法不关联具体的类的对象,可以通过类名直接调用,也就是编译的前期就绑定了,不存在后期动态绑定,也就是不能实现多态。子类的非静态方法是与具体的对象绑定的,两者有着不同的含义。

B、子类的静态方法“覆盖”父类静态方法。

这个覆盖依然是带引号的。事实上把上面那个例子Child类的print方法前面加上static修饰符,确实能通过编译!但是不要以为这就是多态!多态的特点是动态绑定,看下面的例子:


class Father{
   static void print(){
     System.out.println ( " in father  method " );
   }
}
class Child extends Father{
   static void print(){
     System.out.println ( " in child method " );
   }
}

class Test{
   public static void main (String[] args) {
     Father f = new Child();
     f.print();
   }
}

输出结果是:in father method

从这个结果可以看出,并没有实现多态。

但是这种形式很迷惑人,貌似多态,实际编程中千万不要这样搞,会把大家搞懵的!

它不符合覆盖表现出来的特性,不应该算是覆盖!

总而言之,静态方法不能被覆盖。

2、静态方法可以和非静态方法一样被重载。

这样的例子太多了,我不想写例程了。看看java类库中很多这样的例子。

如java.util.Arrays类的一堆重载的binarySearch方法。

在这里提一下是因为查资料时看到这样的话“sun的SL275课程说,静态方法只能控制静态变量(他们本身没有),静态方法不能被重载和覆盖……”

大家不要相信啊!可以重载的。而且静态与非静态方法可以重载。

从重载的机制很容易就理解了,重载是在编译时刻就决定的了,非静态方法都可以,静态方法怎么可能不会呢?

The above is the detailed content of Detailed explanation of Java overloading, rewriting, and constructors. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn