构造函数和方法之间的区别
Bellow是我在Tutorials Points上找到的一个例子,它是一个构造函数的例子。 我得到了大部分,但我不明白为什么你需要一个构造函数和一个方法。
public Puppy(String name){ System.out.println("Passed Name is :" + name ); }
我的问题是,是什么阻止你做这个呢?
public static void Puppy(String name){ System.out.println("Passed Name is: "+name); }
一旦打电话,这两个人不会做同样的事吗?
以下是完整的参考程序:
public class Puppy { int puppyAge; public Puppy(String name) { System.out.println("Passed Name is :" + name); } public void setAge(int age) { puppyAge = age; } public int getAge() { System.out.println("Puppy's age is :" + puppyAge); //what does this return do? since the puppyAge is already printed above. return puppyAge; } public static void main(String []args){ Puppy myPuppy = new Puppy("tommy"); myPuppy.setAge(2); myPuppy.getAge(); System.out.println("Variable Value :" + myPuppy.puppyAge); } }
您没有获得实例的基本概念,这在OOP中是基础。 如果你想要一个比喻,让我们谈谈汽车。
我很确定你知道汽车是什么; 你知道它可以让你从一个地方移动到另一个地方,它有4个轮子,依此类推。 这是一个概念,你车库里的实际车辆是这个概念的一个实例 ( <=>类 )。
构造函数的目标是创建一个实例,而不是打印一些文本。 如果没有构造函数,您将永远无法调用类的非静态方法。 你将无法驾驶汽车的概念,你将需要先建造一辆汽车。
只需回顾这些概念; 没有它,你将无处可去。
我想你的问题是为什么使用…创建构造函数
public Puppy(String name)
…代替…
public static void Puppy(String name)
…, 对?
如果是,首先你应该建立一个构造函数是一个类所拥有的特殊方法 ,只要你创建该类的新实例就会调用它。 所以,例如,如果你有这个课……
public class Clazz { public Clazz (String s) { System.out.println(s); } }
…,然后每当你创建这个类的新实例时…
Clazz c = new Clazz("Hello World");
…,将调用构造函数并执行该方法。 (在此示例中,它将在屏幕上打印“Hello World”。)
也就是说,您可以看到构造函数是一个方法,但它是一个在实例化类时调用的特殊方法。 所以,关于你的问题,构造函数这种方式而不是常规方法头的原因是向编译器指示它是构造函数而不是常规方法。 如果你编写public void Clazz ()
而不是public Clazz ()
,那么编译器将无法识别你的构造函数,并认为它只是一个常规方法。
请注意,构造函数永远不会返回任何内容,因此不必使用void关键字。 此外,将构造函数设置为静态是没有意义的,因为在实例化新对象时会调用构造函数。
构造函数是方法,但它们是特殊类型的方法。 构造函数是没有返回类型的方法,必须以它们的封闭类命名。 那么为什么我们需要构造函数呢? 好吧,这就是我们如何创建类的实例。 当您想要创建某个类的实例时,可以通过调用其构造函数来实现。 构造函数为对象保留内存并返回对新创建的对象的引用。
在Java Spec for Constructors中陈述:
-
构造函数不返回任何内容,因此它们没有返回类型。
在所有其他方面,构造函数声明看起来就像没有结果的方法声明(第8.4.5节 )。
-
您不能覆盖构造函数。
构造函数声明不是成员。 它们永远不会被遗传,因此不会被隐藏或覆盖。
-
它们不能直接访问实例变量,而是必须使用
this
和super
来委托类的变量。构造函数体中的显式构造函数调用语句可能不引用此类或任何超类中声明的任何实例变量或实例方法或内部类,或者在任何表达式中使用this或super; 否则,发生编译时错误。
构造函数和方法之间存在很大差异。 当你实例化一个像在程序中完成的对象时
Puppy myPuppy = new Puppy( "tommy" );
使用new关键字,JVM调用构造函数来创建对象。 因此构造函数会创建不存在的对象,但方法与存在的对象相关联。 您可以在此链接阅读更多信息http://www.javaworld.com/article/2076204/core-java/understanding-constructors.html
关于构造函数的几个好答案。
一个小问题; 您不能拥有与您的类同名的静态方法。 该名称保留给构造函数。
构造函数应该用于设置对象,其中方法只是对对象执行某些操作。 Java是面向对象的,因此整个语言围绕着对象。 构造函数也不能返回任何内容,并且必须与new一起使用才能返回创建的对象的实例,其中方法可以返回任何内容或根本不返回任何内容。
对于该示例,您不需要构造函数。 这是一个非常糟糕的例子。 一种方法也可以。
(如果你没有添加一个类,所有Java类都有一个默认构造函数,所以你仍然可以调用new Puppy()
来获取一个实例。)
当你创建一个对象的新实例( Puppy doggy = new Puppy("Bobby");
)时会立即调用构造函数。 它构造了新对象。 它用“Bobby”这个名称构造它。 (小狗出生时的名字叫“鲍比”)。 假设我们的小狗对它的名字不满意,你想把它改成“史努比”。 然后你会调用方法: doggy.setName("Snoopy")
;
Constructor
函数就是这样,它“构造”您正在创建它的对象技术上是一种特定类型的Method
。 Method
用于修改对象,主要用于执行单个逻辑。 见: single responsibility principle
。
类/方法应该是简单的并且处理确切的信息片段,例如,如果你想要它的属性是长度,宽度,高度,体积,面积等等,那么你的构造函数必须是:
public Shape (double length, double width, double height, double volume, double area, ect...) { //code here }
(注意这个方法的名称应该与类的名称相同,表示’Constructor`)
这就是所谓的code smell
,具体来说:参数太多了。 它很难阅读,不是很有条理,也不是编写代码的坏方法。 因此,方法用于设置这些变量:
public void setLength(double length) { //code here }
那么你的构造函数只会是:
public Shape() { //code here }
这只是一个简单的例子。 在许多情况下,您可能希望根据具体情况将参数(或一些参数)传递给构造函数。
构造函数是一种方法。 特别是在实例化该类的对象时调用它。 所以在你的例子中,如果你写:
Puppy pup = new Puppy("Rover");
您创建一个名为pup
的对象并实例化该对象,允许您使用它。 通过实例化它,你可以调用指定的构造函数,在这种情况下: public Puppy(String name)
将print设置为"Rover"
,但这并不是一个很好的构造函数。 更有意义的是拥有String puppyName;
作为字段变量,并使用this.puppyName = name
将p.puppyName
设置p.puppyName
等于构造函数中传递的内容。
构造函数是public Class(){定义需要在整个类方法中使用的变量是在构造函数下使用public void methodName(){}你可以将void更改为你想要方法返回特定类型的变量类型。
我真的宁愿读一本关于OOP概念的书,在本例中是java,而不是阅读所有(好的)答案。 你可能会得到很多答案,因为这个问题相当受欢迎,但答案不会涉及所有必要的细节。
但有一点我想简单提一下:
public int getAge() { System.out.println("Puppy's age is :" + puppyAge); //what does this return do? since the puppyAge is already printed above. return puppyAge; }
方法可以返回某种答案 。 那么这种方法有什么用呢? 它返回保存在变量中的值,其名称为puppyAge
,它是一个整数。 因此,如果您调用方法myPuppy.getAge()
,此方法中的所有内容(实际上也是打印输出)都将被处理,然后返回。 在您的情况下,您不会将返回值保存在任何地方。 但你要做的“正常”事情是通过这种方法访问小狗的年龄,并实际上用它做一些事情,比如计算你所有的小狗和东西的平均年龄。 当然,您可以从类外部访问变量,因为您没有设置可见性修饰符,如public,private,protected。
public class Puppy { int puppyAge;
实际上没有公共修饰符也有意义,但这与现在不相关。 所以你想要做的是将它设置为私有:
private int age;
并通过像getAge()
这样的方法访问它,并使用它做一些事情:
int allAgesummed = puppy1.getAge() + puppy2.getAge() + puppy3.getAge();
最后,如果您只想在控制台上打印出年龄,那么您的方法应该只完成那一件事并且应该相应地命名,例如:
public void printAgeToConsole(){ System.out.println("Age: " + age); }
void
表示此方法执行某些操作,但不返回任何内容。
您的第一个示例是在实际创建Puppy时调用的公共构造函数。 通常,构造函数会保存名称而不是显示它并将其丢弃,因此您可以稍后再参考它,例如:
public class Puppy{ private String puppyName; public Puppy(String name){ puppyName = name; } public void bark(){ System.out.println(puppyName + ": woof!"); } ... } ... public static void main(){ Puppy Spot = new Puppy("Spot"); // here, the constructor is called, which saves the name // "Spot" into the variable Spot.puppyName. Puppy Fido = new Puppy("Fido"); // on this line, the constructor is called again, but this time, the string // "Fido" is saved into Fido.puppyName. Spot.bark(); // output: "Spot: woof!" }
我认为构造函数是一个“返回”Puppy对象的方法,这就是它没有返回类型的原因。 与小狗的名字不同,声明为静态的方法和变量不特别“属于”任何对象,而是在类的所有成员之间共享。
public class Puppy{ ... private static String latinName; public static void setLatinName(String newLatinName){ latinName = newLatinName; } public static void printLatinName(){ System.out.println("I am a " + latinName + "."); } }; ... static void main(){ Puppy Spot("Spot"); Puppy Fido("Spot"); Spot.setLatinName("Canis Lupus"); Fido.setLatinName("Canis Lupus Familiaris"); Spot.printLatinName(); // output: "I am a Canus Lupus Familiaris." // even though we used the Fido object to change the latinName string, // the output of Spot's non-static method still reflects the change because // latinName is a static field: there is only one String latinName // shared among all members of the class. }
虽然您可以使用Puppy对象来调用静态方法(如果Puppy是多态Canine,这可能特别有用),反之亦然!
public class Puppy{ ... public static void bark(){ System.out.println( puppyName + ": woof!"); // this will not compile! } }
在静态函数的上下文中引用非静态数据成员是无效的(并且没有意义)! 静态函数类似于静态变量:在所有成员对象之间只共享一个函数副本。 这意味着您可以调用Puppy.setLatinName()(而不是Spot.setLatinName())。 您不需要使用特定的Puppy对象来调用静态函数:保证静态函数不依赖于任何非静态成员变量(因为它没有任何非变量)。 调用Puppy.bark()是没有意义的,因为类“Puppy”没有puppyName; 每个Puppy都有自己的puppyName。
我希望这有帮助。 面向对象编程非常强大,了解基础知识非常重要! 祝你好运。