简体   繁体   English

传递和设置布尔值-Java / Android

[英]Passing and setting booleans - Java/Android

I have a class like so: 我有一个像这样的课程:

public class Achievements(){

    boolean score100_Earned_Offline;
    boolean score1000_Earned_Offline;

    final String score100 = "xxxxxxxxxx" //where xxxxxxxxxx would be replaced with the achievement's Google Play Games ID
    final  String score1000 = "xxxxxxxxxx" //where xxxxxxxxxx would be replaced with the achievement's Google Play Games ID
}

In my Game class, I check the state of the achievements every tick and act on them as necessary like so (assume all methods to be valid and defined - this is cut down to provide the code necessary to the question)....... 在我的Game类中,我每隔一个滴答检查一次成就状态,并按需要对它们进行操作(假设所有方法都是有效的和已定义的-减少该方法以提供问题所需的代码)..... ..

public class Game(){

    public void checkAchievements(Achievements achievements){

        if (score>=100){
            unlockAchievement(achievements.score100, achievements.score100_Earned_Offline);     
        }

        if (score>1000){
            unlockAchievement(achievements.score100, achievements.score1000_Earned_Offline);  
        }
    }

    public void unlockAchievement(String achievementToUnlock, boolean thisAchievementOfflineFlag){

        //If user is signed in, then we are ready to go, so go ahead and unlock the relevant achievement....
        if (checkSignedIn()){
            Games.Achievements.unlock(getApiClient(), achievementToUnlock);
        //Otherwise, I want to do is set the relevant flag to true so it can be checked when the user does eventually log in
        else{
            thisAchievementOfflineFlag=true;
        }
    }
}

Pass by value 传递价值

In the 'unlockAchievement' method, the boolean 'thisAchievementOfflineFlag' does get set to true if the user is not logged in, however, it doesn't effect the actual boolean that was originally sent into the method (which as you can see is defined in my 'Achievements' class). 在“ unlockAchievement”方法中,如果用户未登录,则布尔值“ thisAchievementOfflineFlag”的确设置为true,但是,它不会影响最初发送到该方法中的实际布尔值(如您所见,已定义)在我的“成就”课程中)。 I'm guessing this is because Java is Pass by Value and is therefore, creating a local copy of the variable which is valid inside the method only. 我猜这是因为Java是按值传递,因此正在创建仅在方法内部有效的变量的本地副本。 I did try using Boolean too (wrapper class) but got the same results. 我也尝试过使用布尔型 (包装类),但是得到了相同的结果。

Other ways to achieve this? 其他实现此目的的方法?

I've currently got it set up so I can define each achievement as an enum so each one will have it's own copy of the boolean flag. 我目前已经设置好了,因此我可以将每个成就定义为一个枚举,以便每个成就都有自己的boolean标志副本。 However, I'm aware that it's not recommended to use enums in Android so if there is a better way that I am missing, I would rather avoid them. 但是,我知道我们不建议在Android中使用枚举,因此,如果缺少更好的方法,我宁愿避免使用它们。

Please note that I don't want to use if checks or switch statements as this is taking place in a game-loop. 请注意,我不想,如果支票或switch语句,因为这是发生在一个游戏循环使用。

Any suggestions appreciated 任何建议表示赞赏

This is all because Java's implementation of Boolean (also, for example String) is immutable for safety reasons. 这是因为Java的Boolean(例如String)实现出于安全原因是不变的。 You can see it here: http://www.explain-java.com/is-string-mutable-in-java-why-wrapper-classes-immutable-in-java/ 您可以在这里看到它: http : //www.explain-java.com/is-string-mutable-in-java-why-wrapper-classes-immutable-in-java/

You can solve your problem by introducing an object wrapper for that boolean: 您可以通过为该布尔值引入对象包装来解决您的问题:

public class BooleanWrapper {

    private boolean value;

    public void set(boolean value) {
        this.value = value;
    }

    public boolean get() {
        return value;
    }
}

Now, this object reference will be passed by value but will still point to the same BooleanWrapper object on the heap . 现在,此对象引用将按值传递,但仍指向堆上的同一BooleanWrapper对象。 You can simply use getters and setters to change the inner boolean value. 您可以简单地使用getter和setter来更改内部布尔值。

Then your code would become: 然后您的代码将变为:

public void unlockAchievement(String achievementToUnlock, BooleanWrapper thisAchievementOfflineFlag){
    if (checkSignedIn()){
        Games.Achievements.unlock(getApiClient(), achievementToUnlock);
    else {
        thisAchievementOfflineFlag.set(true);
    }
}

Java is pass-by-value: Java是按值传递的:

When you pass boolean then you for sure passed it by value, while it is a primitive type. 当您传递boolean值时,您肯定会按值传递它,而它是原始类型。 When you pass Boolean , you would think it's an object and that you can change it's state, but actually you cannot because Boolean is implemented as an immutable object (as already said). 当您传递Boolean ,您会认为它是一个对象并且可以更改其状态,但是实际上您不能这样做,因为Boolean是作为不可变对象实现的( 如上所述 )。 You can confirm this just by reading the code of java.lang.Boolean . 您只需阅读java.lang.Boolean的代码即可确认这一点。

But if you create your own wrapper class, and in a sense, you control whether you implement it in immutable or mutable way. 但是,从某种意义上说,如果您创建自己的包装器类,则可以控制是以不可变还是可变的方式实现它。 BooleanWrapper I wrote lets you change the state of that object. 我编写的BooleanWrapper可让您更改该对象的状态。 And when you pass an object such as this one to the method, it's passed by value. 当您将一个这样的对象传递给方法时,它会按值传递。 That means that another reference is created, but it points to the same object on heap (see image below). 这意味着将创建另一个引用,但它指向堆上的同一对象(请参见下图)。

在此处输入图片说明

您可以使用AtomicBoolean ,它具有按引用传递的语义。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM