【问题标题】:Purpose of a constructor in Java?Java中构造函数的目的?
【发布时间】:2013-11-25 08:21:55
【问题描述】:

构造函数的目的是什么?我在学校一直在学习 Java,在我看来,在我们迄今为止所做的事情中,构造函数在很大程度上是多余的。是否有目的还有待观察,但到目前为止,这对我来说似乎毫无意义。比如下面两个sn-ps的代码有什么区别?

public class Program {    
    public constructor () {
        function();
    }        
    private void function () {
        //do stuff
    }    
    public static void main(String[] args) { 
        constructor a = new constructor(); 
    }
}

这就是我们被教导如何做作业的方式,但下面的人不会做同样的事情吗?

public class Program {    
    public static void main(String[] args) {
        function();
    }        
    private void function() {
        //do stuff
    }
}

构造函数的目的没有让我明白,但话说回来,到目前为止我们所做的一切都非常初级。

【问题讨论】:

  • 那不是构造函数。事实上,它甚至根本不构造类。构造函数看起来像public Program(){\\...,并且会被调用new Program()

标签: java function methods constructor


【解决方案1】:

构造函数用于初始化类的实例。您通常使用构造函数来创建新对象,其中的参数指定初始状态或有关对象的其他重要信息

来自official Java tutorial

类包含构造函数,这些构造函数被调用以从类蓝图创建对象。构造函数声明看起来像方法声明——除了它们使用类的名称并且没有返回类型。例如,Bicycle 有一个构造函数:

public Bicycle(int startCadence, int startSpeed, int startGear) {
    gear = startGear;
    cadence = startCadence;
    speed = startSpeed;
}

要创建一个名为 myBike 的新 Bicycle 对象,new 运算符会调用构造函数:

自行车 myBike = new Bicycle(30, 0, 8);

new Bicycle(30, 0, 8) 在内存中为对象创建空间并初始化其字段。

虽然 Bicycle 只有一个构造函数,但它可以有其他构造函数,包括无参数构造函数:

公共自行车(){ 齿轮 = 1; 节奏= 10; 速度 = 0; }

Bicycle yourBike = new Bicycle(); 调用无参数构造函数来创建一个名为 yourBike 的新 Bicycle 对象。

【讨论】:

  • 要么你不了解他,要么他不了解构造函数对它们有什么用处。假设你的程序是一个纸牌游戏:你想要一个名为 Card 的类的 52 个实例,每个实例都有一个数字和一个颜色。构造函数用于创建类 Card 的实例。您需要调用 52 次才能拥有 52 张卡片:new Card(1, "hearts") 等。现在 Player 的每个实例(您还需要一个构造函数)可以拥有一个卡片列表(使用构造函数构造)。阅读介绍性 Java 书籍或官方 Java 教程。
  • 干杯,这消除了我的困惑。设置默认或初始参数是有意义的,但在我们迄今为止所做的一切中,这并不是必需的。我想我们已经为需要保持一致性做好了准备。
  • 谁对我投了反对票,请解释一下原因?从我的回答来看,我绝对不会以任何方式损害 OP 对构造函数的了解。 ://
  • @LotusUNSW 我感觉这里有一个反对票的巨魔。你的回答很好。
  • @AJMansfield - 不正确。您可以在超类中放置额外的构造函数,并在子类中仍然使用默认构造函数,只要超类包含一个显式的、可访问的、不带参数且没有 throws 子句的构造函数。一个类可以包含多个构造函数。要提供的构造函数的选择可以基于可用于初始化实例的参数集。有时这些参数必须在构造函数中指定,因为它们在实例中是不变的。
【解决方案2】:

构造函数基本上是一种方法,您可以使用它确保您的类的对象天生有效。这是构造函数的主要动机。

假设您希望您的类有一个整数字段,该字段应始终大于零。您如何以可靠的方式做到这一点?

public class C {
     private int number;

     public C(int number) {
        setNumber(number);
     }

     public void setNumber(int number) {
        if (number < 1) {
            throws IllegalArgumentException("C cannot store anything smaller than 1");
        }
        this.number = number;
     }
}

在上面的代码中,您可能看起来像是在做一些多余的事情,但实际上您是在确保无论如何该数字始终有效。

“初始化类的实例”是构造函数做什么,但不是为什么我们有构造函数的原因。问题是关于构造函数的目的。你也可以在外部初始化一个类的实例,在上面的例子中使用c.setNumber(10)。所以构造函数并不是初始化实例的唯一方法。

构造函数这样做,但以一种安全的方式。换句话说,一个类单独解决了确保其对象始终处于有效状态的整个问题。不使用构造函数会将此类验证留给外部世界,这是糟糕的设计。

这是另一个例子:

public class Interval {
    private long start;
    private long end;

    public Interval(long start, long end) {
        changeInterval(start, end);
    }

    public void changeInterval(long start, long end) {
        if (start >= end) {
            throw new IllegalArgumentException("Invalid interval.");
        }
        this.start = start;
        this.end = end;
    }
    public long duration() {
        return end - start;
    }
}

Interval 类表示一个时间间隔。时间使用 long 存储。在开始之前结束的间隔没有任何意义。通过使用像上面这样的构造函数,不可能在任何给定时刻在系统中的任何地方都有一个 Interval 的实例来存储一个没有意义的间隔。

【讨论】:

  • 一般来说,(非最终类的)构造函数应该只调用最终或私有方法。 stackoverflow.com/questions/4893558/…
  • +1 表示务实的答案。这个答案不仅满足了定义,而且满足了我的 WHY 查询。 “生而有效”是我缺少的一小部分“有用性”,以消除使用构造函数的必要性。
  • 我知道这是非常古老的,但这是思考“为什么”的好方法。假设您制作了一个联系人列表应用程序。您拥有 100 个联系人的地址,以及一个保存“有效”电话号码的构造函数。每个成员都使用有效的电话号码进行初始化?
  • 正确。如果您将电话号码表示为类或地址类的字段,您可能希望在创建包含此类信息的对象之前验证电话号码。将对象视为创建后不一定会受到您严格控制的事物。例如,您的对象可能最终被您未编写的代码使用。所以你的对象应该有意义。构造函数是一种表示不允许任何对象以违反其语义的方式存在的方式。
【解决方案3】:

正如 LotusUNSW 回答中提到的 构造函数用于初始化类的实例。

例子:

假设你有一个类似Animal 的类

class Animal{
   private String name;
   private String type;
}

让我们看看当你尝试创建一个 Animal 类的实例时会发生什么,比如一个名为 PuppyDog。现在你必须初始化name = Puppytype = Dog。那么,你怎么能做到这一点。一种方法是使用像

这样的构造函数
    Animal(String nameProvided, String typeProvided){
         this.name = nameProvided;
         this.type = typeProvided;
     }

现在,当您创建 Animal 类的对象时,类似 Animal dog = new Animal("Puppy", "Dog"); 的构造函数将被调用并将名称和类型初始化为您提供的值,即分别为 Puppy 和 Dog。

现在你可能会问,如果我没有为我的构造函数提供类似

的参数会怎样
Animal xyz = new Animal();

这是一个default Constructor,它使用默认值初始化对象,即在我们的Animal类中,nametype对应于xyz对象的值将是name = nulltype = null

【讨论】:

    【解决方案4】:

    构造函数在创建对象时对其进行初始化。它 与其 类 同名 并且 在 语法 上 类似于 一个 方法 , 但 构造 函数 没有 明确 的 返回 类型 . 通常 我们 使用 构造 函数 为 类 定义 的 实例 变量 赋予 初始 值 , 或 执行 任何 其他 操作 .制作完全成形的对象所需的启动程序。

    这是一个构造函数的例子:

    class queen(){
       int beauty;
    
       queen(){ 
         beauty = 98;
       }
     }
    
    
    class constructor demo{
        public static void main(String[] args){
           queen arth = new queen();
           queen y = new queen();
    
           System.out.println(arth.beauty+" "+y.beauty);
    
        }
    } 
    

    输出是:

    98 98
    

    这里的构造函数是:

    queen(){
    beauty =98;
    }
    

    现在轮到参数化构造函数了。

      class queen(){
       int beauty;
    
       queen(int x){ 
         beauty = x;
       }
     }
    
    
    class constructor demo{
        public static void main(String[] args){
           queen arth = new queen(100);
           queen y = new queen(98);
    
           System.out.println(arth.beauty+" "+y.beauty);
    
        }
    } 
    

    输出是:

    100 98
    

    【讨论】:

      【解决方案5】:
      • 通过构造函数(带参数),您可以“询问”该类的用户所需的依赖项。
      • 用于初始化实例变量
      • 并将参数传递给超类 (super(...)) 的构造函数,其作用基本相同
      • 它可以使用可能引发异常的代码初始化(最终)实例变量,而不是 instance initializer 范围
      • 不应不要盲目地从构造函数中调用方法,因为在本地或派生类中初始化可能未完成/不够。

      【讨论】:

      • 实例初始化作用域可以抛出异常,只要声明所有的构造函数都抛出相同的异常。
      【解决方案6】:

      Java 构造函数的名称与其所属的类的名称相同。

      构造函数的语法不包含返回类型,因为构造函数从不返回值。

      构造函数总是在创建对象时被调用。 示例:- 默认构造函数

      class Student3{  
          int id;  
          String name;  
          void display(){System.out.println(id+" "+name);}  
          public static void main(String args[]){  
              Student3 s1=new Student3();  
              Student3 s2=new Student3();  
              s1.display();  
              s2.display();  
          }  
      } 
      

      输出:

      0 null
      0 null
      

      说明: 在上面的类中,您没有创建任何构造函数,因此编译器为您提供了一个默认构造函数。这里默认构造函数提供了 0 和 null 值。

      参数化构造函数示例

      在这个例子中,我们创建了有两个参数的 Student 类的构造函数。构造函数中可以有任意数量的参数。

      class Student4{  
          int id;  
          String name;  
          Student4(int i,String n){  
              id = i;  
              name = n;  
          }  
          void display(){System.out.println(id+" "+name);}  
          public static void main(String args[]){  
              Student4 s1 = new Student4(111,"Karan");  
              Student4 s2 = new Student4(222,"Aryan");  
              s1.display();  
              s2.display();  
          }  
      }  
      

      输出:

      111 Karan
      222 Aryan
      

      【讨论】:

      • 这篇文章有一些严重的格式问题。请编辑以使用代码块。
      【解决方案7】:

      用于设置类的内容和状态。 虽然确实可以使用 main 方法制作更简单的示例,但每个应用程序只有 1 个 main 方法,因此它不是一种明智的方法。

      考虑简单地启动程序的 main 方法,并且应该只知道如何执行此操作。还要注意 main() 是静态的,因此不能调用需要类实例和相关状态的函数。 main 方法应该调用 new Program().function() 并且 Program 构造函数不应该调用 function(),除非它是设置类所必需的。

      【讨论】:

        【解决方案8】:

        类定义为您的类定义 API。换句话说,它是一个蓝图,它定义了存在于类和它的客户之间的契约——所有其他使用这个类的代码。合约指明了哪些方法可用、如何调用它们以及期望得到什么回报。

        但是类定义是一个规范。在您拥有此类的实际对象之前,合同只是“一张纸”。这就是构造函数的用武之地。

        构造函数是通过在内存中创建对象并返回对它的引用来创建类实例的方法。 应该在构造函数中发生的事情是对象处于适当的初始状态,以便对对象的后续操作有意义。

        从构造函数返回的这个对象现在将遵守类定义中指定的约定,您可以使用这个对象做实际的工作。

        这样想。如果您查看保时捷网站,您会看到它可以做什么——马力、扭矩等。但是,除非您有一辆真正的保时捷可以驾驶,否则它并不有趣。

        希望对您有所帮助。

        【讨论】:

          【解决方案9】:

          构造函数主要用于在创建对象时初始化变量

          【讨论】:

            【解决方案10】:

            我认为构造函数可能像数据库一样工作,只有它定义变量和控制它们的方法

            然后我看到了使用未在其构造函数中定义的变量和方法的对象。因此,对我来说最有意义的讨论是测试变量值的有效性,但是该类可以创建未在构造函数中定义的变量和方法 - 不像数据库,更像是蒸汽上的过压阀机车。它不控制车轮等。

            定义比我想象的要少。

            【讨论】:

            • 这不能回答问题
            【解决方案11】:

            构造函数将有助于防止实例获得不真实的值。例如,使用身高、体重设置 Person 类。不可能有0m和0kg的人

            【讨论】:

              【解决方案12】:

              假设我们正在存储 3 个学生的学生详细信息。这 3 名学生的 sno、sname 和 sage 值不同,但所有 3 名学生都属于同一部门的 CSE。因此最好在构造函数中初始化“dept”变量,以便所有 3 个学生对象都可以获取该值。

              要理解清楚,请看下面的简单示例:

              class Student
              {
                  int sno,sage;
                  String sname,dept;
                  Student()
                  {
                      dept="CSE";
                  }
                  public static void main(String a[])
                  {
                      Student s1=new Student();
                      s1.sno=101;
                      s1.sage=33;
                      s1.sname="John";
              
                      Student s2=new Student();
                      s2.sno=102;
                      s2.sage=99;
                      s2.sname="Peter";
              
              
                      Student s3=new Student();
                      s3.sno=102;
                      s3.sage=99;
                      s3.sname="Peter";
                      System.out.println("The details of student1 are");
                      System.out.println("The student no is:"+s1.sno);
                      System.out.println("The student age is:"+s1.sage);
                      System.out.println("The student name is:"+s1.sname);
                      System.out.println("The student dept is:"+s1.dept);
              
              
                      System.out.println("The details of student2 are");`enter code here`
                      System.out.println("The student no is:"+s2.sno);
                      System.out.println("The student age is:"+s2.sage);
                      System.out.println("The student name is:"+s2.sname);
                      System.out.println("The student dept is:"+s2.dept);
              
                      System.out.println("The details of student2 are");
                      System.out.println("The student no is:"+s3.sno);
                      System.out.println("The student age is:"+s3.sage);
                      System.out.println("The student name is:"+s3.sname);
                      System.out.println("The student dept is:"+s3.dept);
                  }
              }
              

              输出:

              student1的详细信息是
              学生编号是:101
              学生年龄:33
              学生姓名是:约翰
              学生部门是:CSE
              student2的详细信息是
              学生编号是:102
              学生年龄:99
              学生姓名是:彼得
              学生部门是:CSE
              student2的详细信息是
              学生编号是:102
              学生年龄:99
              学生姓名是:彼得
              学生部门是:CSE

              【讨论】:

              【解决方案13】:

              好吧,首先我将在两个代码sn-ps中告诉错误。

              第一个代码sn-p

              public class Program
              {
                  public constructor() // Error - Return type for the method is missing
                  {
                      function();
                  }        
                  private void function()
                  {
                      //do stuff
                  }   
                  
                  public static void main(String[] args)
                  {
                      constructor a = new constructor(); // Error - constructor cannot be resolved to a type
                  }
              }
              

              正如你在上面的代码中看到的,构造函数名和类名不同。在main() 方法中,您正在从一个没有返回类型的方法创建一个对象。

              二码sn-p

              public class Program
              {
                  public static void main(String[] args)
                  {
                      function(); // Error - Cannot make a static reference to the non-static method function() from the type Program
                  }
                  
                  private void function()
                  {
                      //do stuff
                  } 
              }
              

              现在,在这段代码 sn-p 中,您尝试从 Program 类型创建对非静态方法 function() 的静态引用,这是不可能的。

              所以可能的解决方案是这样的,

              第一个代码sn-p

              public class Program
              {
                  public Program()
                  {
                      function();
                  }        
                  private void function()
                  {
                      //do stuff
                  }   
                  
                  public static void main(String[] args)
                  {
                      Program a = new Program();
                      a.function();
                  }
              }
              

              二码sn-p

              public class Program
              {
                  public static void main(String[] args)
                  {
                      Program a = new Program();
                      a.function();
                  }
                  
                  private void function()
                  {
                      //do stuff
                  } 
              }
              

              最后代码sn-ps的区别在于,在第一个代码sn-p中类名和类名不一样

              虽然在第二个代码 sn-p 中没有定义构造函数。

              同时要了解构造函数的用途参考下面的资源,

              https://docs.oracle.com/javase/7/docs/api/java/lang/reflect/Constructor.html

              https://www.flowerbrackets.com/constructor-in-java/

              【讨论】:

                猜你喜欢
                • 2012-11-13
                • 2015-02-22
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2021-03-12
                • 2012-06-30
                • 1970-01-01
                相关资源
                最近更新 更多