Java 在构造函数或声明中初始化类字段?
我最近一直在用C#和Java编程,我很好奇初始化类字段的最佳位置在哪里 我应该在申报时做吗Java 在构造函数或声明中初始化类字段?,java,Java,我最近一直在用C#和Java编程,我很好奇初始化类字段的最佳位置在哪里 我应该在申报时做吗 public class Dice { private int topFace = 1; private Random myRand = new Random(); public void Roll() { // ...... } } 还是在构造函数中 public class Dice { private int topFace;
public class Dice
{
private int topFace = 1;
private Random myRand = new Random();
public void Roll()
{
// ......
}
}
还是在构造函数中
public class Dice
{
private int topFace;
private Random myRand;
public Dice()
{
topFace = 1;
myRand = new Random();
}
public void Roll()
{
// .....
}
}
我真的很好奇你们中的一些老兵认为什么是最好的做法。我想保持一致,坚持一种方法。我的规则:
null
,false
,0
,0.0
…)假设您的示例中的类型,您肯定更喜欢初始化构造函数中的字段。例外情况如下:
- 静态类/方法中的字段
- 键入为static/final/et al的字段
我总是认为类顶部的字段列表是目录(此处包含的内容,而不是如何使用),构造函数是介绍。方法当然是章节。如果我告诉你,那要看情况了 我通常会初始化所有东西,并以一致的方式进行初始化。是的,它过于明确,但也更容易维护 如果我们担心性能,那么我只初始化必须做的事情,并将其放在最划算的地方 在实时系统中,我甚至怀疑是否需要变量或常量
和C++中,我通常在任何地方不进行初始化,并将其移动到一个In()函数中。为什么?那么,在C++中,如果你在对象构造过程中初始化了一个可以抛出异常的东西,那么你就打开了内存泄漏。
我通常尝试构造函数什么也不做,但是获取依赖关系并用它们初始化相关实例成员。如果你想对你的类进行单元测试,这将使你的生活更轻松 如果要分配给实例变量的值不受要传递给构造函数的任何参数的影响,则在声明时分配它。在C#中,这无关紧要。您给出的两个代码示例完全相同。在第一个示例中,C#编译器(或者是CLR?)将构造一个空构造函数并初始化变量,就像它们在构造函数中一样(Jon Skeet在下面的注释中解释了这一点)。 如果已经有一个构造函数,则“上面”的任何初始化都将移到构造函数的顶部就最佳实践而言,前者比后者更不容易出错,因为有人可能很容易添加另一个构造函数并忘记链接它。在声明中设置值有一点性能优势。如果在构造函数中设置它,它实际上会被设置两次(首先设置为默认值,然后在构造函数中重置) 这里C#的语义与Java略有不同。在C#中,声明中的赋值在调用超类构造函数之前执行。在Java中,它是紧接着完成的,允许使用“this”(对于匿名内部类特别有用),这意味着这两种形式的语义确实匹配
如果可以,请将字段设置为最终字段。我认为有一个警告。我曾经犯过这样一个错误:在派生类中,我试图“在声明时初始化”从抽象基类继承的字段。结果是存在两组字段,一组是“base”,另一组是新声明的字段,调试花费了我相当多的时间
教训:要初始化继承的字段,您需要在构造函数内部执行。有许多不同的情况
public class AdminTeam
{
private List<string> usernames = new List<string>();
public AdminTeam()
{
}
public AdminTeam(List<string> admins)
{
admins.ForEach(x => usernames.Add(x));
}
}
我只需要一个空列表
情况很清楚。我只需要准备我的列表,防止在有人向列表中添加项目时引发异常
public class CsvFile
{
private List<CsvRow> lines = new List<CsvRow>();
public CsvFile()
{
}
}
公共类CsvFile
{
私有列表行=新列表();
公共CsvFile()
{
}
}
我知道这些值
我完全知道默认情况下我想要什么值,或者我需要使用一些其他逻辑
public class AdminTeam
{
private List<string> usernames;
public AdminTeam()
{
usernames = new List<string>() {"usernameA", "usernameB"};
}
}
公共类管理员团队
{
私人名单用户名;
公共行政小组()
{
usernames=newlist(){“usernameA”,“usernameB”};
}
}
或
公共类管理员团队
{
私人名单用户名;
公共行政小组()
{
usernames=GetDefaultUsers(2);
}
}
带有可能值的空列表
有时,我希望默认情况下会出现一个空列表,并可能通过另一个构造函数添加值
public class AdminTeam
{
private List<string> usernames = new List<string>();
public AdminTeam()
{
}
public AdminTeam(List<string> admins)
{
admins.ForEach(x => usernames.Add(x));
}
}
公共类管理员团队
{
私有列表用户名=新列表();
公共行政小组()
{
}
公共管理员团队(列出管理员)
{
ForEach(x=>usernames.Add(x));
}
}
在Java中,带有声明的初始值设定项意味着字段总是以相同的方式初始化,无论使用哪个构造函数(如果有多个)或构造函数的参数(如果有参数),尽管构造函数可能随后更改值(如果不是最终值)。因此,使用带有声明的初始值设定项向读者建议,无论使用哪个构造函数,也不管传递给任何构造函数的参数如何,初始化值都是字段在所有情况下都具有的值。因此,仅当且始终当所有构造对象的值相同时,才使用带有声明的初始值设定项。C#的设计建议首选内联初始化,否则不会使用该语言。任何时候都可以避免c语言中不同位置之间的交叉引用
class MyGeneric<T>
{
T data;
//T data = ""; // <-- ERROR
//T data = 0; // <-- ERROR
//T data = null; // <-- ERROR
public MyGeneric()
{
// All of the above errors would be errors here in constructor as well
}
}
class MyGeneric<T>
{
T data = default(T);
public MyGeneric()
{
// The same method can be used here in constructor
}
}