java不可变类:空白的最后字段可能未被初始化

mqkwyuun  于 2021-06-30  发布在  Java
关注(0)|答案(3)|浏览(326)

我必须做一个不变的类,但我给了一个错误。

public final class ClassX{
   private final String a;
   private final String b;
   private final int c;

   public ClassX(String a, String b, int c){
       this.a=a;
       this.b=b;
       if(c>=1||c<=100)
       this.c=c;
   }

空白最终字段C可能尚未初始化。
我做错什么了吗?
没有,如果我没有得到任何错误,但我需要变量c在1-100范围内

lh80um4z

lh80um4z1#

平衡你的if和else

用你的话来说:

if( … ) { this.c = c ; }

…你还没有解决这个案子。如果测试在 if a中的测试结果 false ,您的成员字段 this.c 不会被你赋值。这个领域的成员 int 将被指定一个默认值为零。
(对于与基本体不同的对象引用,默认值为 null . 这意味着在该成员字段中没有任何值。)
我们可以在下面的代码示例中看到这种默认行为。

package work.basil.example;

public class DefaultingInt
{
    private int count;

    public int getCount ( ) { return this.count; }  // Getter method (accessor). 

    @Override
    public String toString ( )
    {
        return "DefaultingInt{ " +
                "count=" + count +
                " }";
    }

    public static void main ( String[] args )
    {
        DefaultingInt di = new DefaultingInt();
        System.out.println( "di = " + di );
    }
}

运行时:
di=defaultingint{count=0}
使用上面的代码,成员字段的值可以在以后更改为其他代码。

final需要赋值

您的代码增加了标记成员字段的复杂性 final . 使用 final 意味着您打算赋值一次,作为常量。编译器确保不允许任何代码更改该值。
ide或编译器正在标记错误,因为 if 测试返回 false ,则不会为 final 现场。构造函数结束后,以后不能赋值。由于您坚持要立即设置一个最终值,并且您的代码在运行时可能会错过两次设置该值的机会(静态赋值,或在构造函数中),因此编译器知道出了问题。

解决方案:添加else

去处理失踪的案子 if 返回一个 false ,更改代码以添加 else 阻止。

if( … ) { this.c = c ; } else { this.c = your-default-value-here ; }

正如其他人所指出的那样,你的 if 测试有缺陷。使用逻辑and而不是or。

if( ( c >= 1 ) && ( c <= 100 ) )  // If input value is within the bounds allowed, assign to field.
{ 
    this.c = c ; 
} 
else // Else input value is outside the bounds allowed.
{ 
    this.c = your-default-value-here ; 
}

如果无法指定默认值,则引发异常。

if( ( c >= 1 ) && ( c <= 100 ) )  // If input value is within the bounds allowed, assign to field.
{ 
    this.c = c ; 
} 
else // Else input value is outside the bounds allowed. Throw exception.
{ 
    throw new  IllegalArgumentException( "Requires an input value of 1 to 100 inclusive." ) ;
}

完整示例代码:

package work.basil.example;

public class DefaultingInt
{
    final private int count;

    public DefaultingInt ( int count )
    {
        if ( ( count >= 1 ) && ( count <= 100 ) )  // If input value is within the bounds allowed, assign to field.
        {
            this.count = count;
        } else // Else input value is outside the bounds allowed. Throw exception.
        {
            throw new IllegalArgumentException( "Requires an input value of 1 to 100 inclusive." );
        }
    }

    public int getCount ( ) { return this.count; }  // Getter method (accessor). 

    @Override
    public String toString ( )
    {
        return "DefaultingInt{ " +
                "count=" + count +
                " }";
    }

    public static void main ( String[] args )
    {
        DefaultingInt di = new DefaultingInt( 101 );
        System.out.println( "di = " + di );
    }
}

运行时:
线程“main”java.lang.illegalargumentexception中出现异常:要求输入值为1到100(含1到100)。

java记录

顺便说一下,对于一个主要任务是承载数据的简单不可变对象,可以考虑使用新的记录特性,因为它将在Java16中出现,并在早期版本中预览。
只需声明成员字段。java隐式地创建 toString , equals ,和 hashCode .
记录、标记 final 在成员字段上是多余的。记录中的每个成员字段都是隐式的 final ,一个只读常量,具有隐式getter访问器方法。记录意味着是一个不可修改的命名元组(命名字段的不可变分类)。记录的成员字段引用的对象中的内容可能与任何其他类一样是可变的,但不能更改将该特定对象分配给该成员字段的方式。原语,例如 int 字段不是对象引用,而是直接值,当用作记录中的字段时是不可变的。

record ClassX( String a , String b , int c ) {}

您仍然可以提供自己的构造函数来运行 if 数据验证测试。

package work.basil.example;

public record DefaultingInt(int count)
{
    public DefaultingInt ( int count )
    {
        if ( ( count >= 1 ) && ( count <= 100 ) )  // If input value is within the bounds allowed, assign to field.
        {
            this.count = count;
        } else // Else input value is outside the bounds allowed. Throw exception.
        {
            throw new IllegalArgumentException( "Requires an input value of 1 to 100 inclusive." );
        }
    }

    public static void main ( String[] args )
    {
        DefaultingInt di = new DefaultingInt( 42 );
        System.out.println( "di = " + di );
    }
}

运行时:
di=违约IT[计数=42]

pw136qt2

pw136qt22#

this.c = Math.min(100, Math.max(c,1));
tyky79it

tyky79it3#

你的 if 是没用的。
如果你想让c在1-100之间,你应该改变 ||&& 如果您希望每次使用@a.alexander solution时都将c初始化为最大值或最小值

相关问题