5

I am new to kotlin and when I was reading about the data classes in kotlin and I found these code.Its basically a comparision between the java model class and kotlin data class and it was wriiten over there that both the code do the same task.

Code 1

public class VideoGame {

private String name;
private String publisher;
private int reviewScore;

public VideoGame(String name, String publisher, int reviewScore) {
    this.name = name;
    this.publisher = publisher;
    this.reviewScore = reviewScore;
}

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

public String getPublisher() {
    return publisher;
}

public void setPublisher(String publisher) {
    this.publisher = publisher;
}

public int getReviewScore() {
    return reviewScore;
}

public void setReviewScore(int reviewScore) {
    this.reviewScore = reviewScore;
}}

Code 2

data class VideoGame(val name: String, val publisher: String, var reviewScore: Int)

My question is that In the data class all the variable are public and not private and any anyone can directly access the variable with the help of a object of this class but in the java code all the variable are private that's why we have to write the getter and setter for these member variable if it was public there is no need of getter and setter.So how these codes are same?

  • 3
    Actually, the Kotlin version is just syntactic sugar for the Java version. The backing fields themselves are private, I'm pretty sure. See here: https://kotlinlang.org/docs/reference/properties.html – user May 14 '20 at 15:43
  • Can you.please explain it i am new to these things and i am not able to understand it – Abhishek Agarwal May 14 '20 at 15:48

2 Answers2

14

Main use of data class is to ease the work of writing POJOs.

If you get into the IDE and write your VideoGame class:

data class VideoGame(val name: String, val publisher: String, var reviewScore: Int)

And then you de-compile it:

Your IDE Toolbar > Tools > Kotlin > Show Kotlin bytecode > Decompile

You get this:

@Metadata(
   mv = {1, 1, 16},
   bv = {1, 0, 3},
   k = 1,
   d1 = {"\u0000\"\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0000\n\u0002\u0010\u000e\n\u0002\b\u0002\n\u0002\u0010\b\n\u0002\b\r\n\u0002\u0010\u000b\n\u0002\b\u0004\b\u0086\b\u0018\u00002\u00020\u0001B\u001d\u0012\u0006\u0010\u0002\u001a\u00020\u0003\u0012\u0006\u0010\u0004\u001a\u00020\u0003\u0012\u0006\u0010\u0005\u001a\u00020\u0006¢\u0006\u0002\u0010\u0007J\t\u0010\u000f\u001a\u00020\u0003HÆ\u0003J\t\u0010\u0010\u001a\u00020\u0003HÆ\u0003J\t\u0010\u0011\u001a\u00020\u0006HÆ\u0003J'\u0010\u0012\u001a\u00020\u00002\b\b\u0002\u0010\u0002\u001a\u00020\u00032\b\b\u0002\u0010\u0004\u001a\u00020\u00032\b\b\u0002\u0010\u0005\u001a\u00020\u0006HÆ\u0001J\u0013\u0010\u0013\u001a\u00020\u00142\b\u0010\u0015\u001a\u0004\u0018\u00010\u0001HÖ\u0003J\t\u0010\u0016\u001a\u00020\u0006HÖ\u0001J\t\u0010\u0017\u001a\u00020\u0003HÖ\u0001R\u0011\u0010\u0002\u001a\u00020\u0003¢\u0006\b\n\u0000\u001a\u0004\b\b\u0010\tR\u0011\u0010\u0004\u001a\u00020\u0003¢\u0006\b\n\u0000\u001a\u0004\b\n\u0010\tR\u001a\u0010\u0005\u001a\u00020\u0006X\u0086\u000e¢\u0006\u000e\n\u0000\u001a\u0004\b\u000b\u0010\f\"\u0004\b\r\u0010\u000e¨\u0006\u0018"},
   d2 = {"Lcom/yourpackage/VideoGame;", "", "name", "", "publisher", "reviewScore", "", "(Ljava/lang/String;Ljava/lang/String;I)V", "getName", "()Ljava/lang/String;", "getPublisher", "getReviewScore", "()I", "setReviewScore", "(I)V", "component1", "component2", "component3", "copy", "equals", "", "other", "hashCode", "toString", "app"}
)
public final class VideoGame {
   @NotNull
   private final String name;
   @NotNull
   private final String publisher;
   private int reviewScore;

   @NotNull
   public final String getName() {
      return this.name;
   }

   @NotNull
   public final String getPublisher() {
      return this.publisher;
   }

   public final int getReviewScore() {
      return this.reviewScore;
   }

   public final void setReviewScore(int var1) {
      this.reviewScore = var1;
   }

   public VideoGame(@NotNull String name, @NotNull String publisher, int reviewScore) {
      Intrinsics.checkParameterIsNotNull(name, "name");
      Intrinsics.checkParameterIsNotNull(publisher, "publisher");
      super();
      this.name = name;
      this.publisher = publisher;
      this.reviewScore = reviewScore;
   }

   @NotNull
   public final String component1() {
      return this.name;
   }

   @NotNull
   public final String component2() {
      return this.publisher;
   }

   public final int component3() {
      return this.reviewScore;
   }

   @NotNull
   public final VideoGame copy(@NotNull String name, @NotNull String publisher, int reviewScore) {
      Intrinsics.checkParameterIsNotNull(name, "name");
      Intrinsics.checkParameterIsNotNull(publisher, "publisher");
      return new VideoGame(name, publisher, reviewScore);
   }

   // $FF: synthetic method
   public static VideoGame copy$default(VideoGame var0, String var1, String var2, int var3, int var4, Object var5) {
      if ((var4 & 1) != 0) {
         var1 = var0.name;
      }

      if ((var4 & 2) != 0) {
         var2 = var0.publisher;
      }

      if ((var4 & 4) != 0) {
         var3 = var0.reviewScore;
      }

      return var0.copy(var1, var2, var3);
   }

   @NotNull
   public String toString() {
      return "VideoGame(name=" + this.name + ", publisher=" + this.publisher + ", reviewScore=" + this.reviewScore + ")";
   }

   public int hashCode() {
      String var10000 = this.name;
      int var1 = (var10000 != null ? var10000.hashCode() : 0) * 31;
      String var10001 = this.publisher;
      return (var1 + (var10001 != null ? var10001.hashCode() : 0)) * 31 + this.reviewScore;
   }

   public boolean equals(@Nullable Object var1) {
      if (this != var1) {
         if (var1 instanceof VideoGame) {
            VideoGame var2 = (VideoGame)var1;
            if (Intrinsics.areEqual(this.name, var2.name) && Intrinsics.areEqual(this.publisher, var2.publisher) && this.reviewScore == var2.reviewScore) {
               return true;
            }
         }

         return false;
      } else {
         return true;
      }
   }
}

So the backing fields ARE private. Kotlin is doing all the tedious and heavy lifting for you. That is:

  1. Backing fields with getters and setters
  2. Basic implementation of toString
  3. Implementation of equals
  4. Implementation of hashCode
  5. Annotating nullability
  6. Writing the constructor implementation
  7. Adding a useful copy method

You get a whoping 82 lines of bloated code that you maybe would've written yourself (maybe sprinkling some bugs in it?) in Java in exchange of 1 keyword. Isn't it awesome?

So quick recap

  • data class make way easier writing POJOs
  • val tells the compiler to implement a getter for a given property. That property is also going to be immutable within the class itself. (You can't change it in functions belonging to that class)
  • var tells the compiler to provide setter and getters
  • You can set the visibility of properties in the same data class like: data class MyClass(private val prop: Int)

Further examples:

The keywords that you are using infront of val and var only affect the visibility of the getters and setters.

For instance: Public get but private set:

class VideoGame {
      var pegiRating: Int = 0
           private set
}
Some random IT boy
  • 7,569
  • 2
  • 21
  • 47
0

Those don't do the the same task, because the Java version has getters and the Kotlin version does not because the properties are val instead of var. If they were var, then the functionality would all be there (plus Kotlin data classes also have copy functionality and equals, hashcode, and toString implemented for you).

By default (with no custom getter/setter), a Kotlin property (public or not) is like a Java private field with (public or not) getters and/or setters.

In Java, it's usually not recommended to make your fields public so other objects can modify them directly. It's not future-proof, because if you decide for example to have a side effect when changing the value, you have to change the field to private and add a setter. That would break any code that works with the class. To avoid this, fields should be private and the getters and setters can be public, which is unfortunately a lot of boilerplate code.

In Kotlin, you can change a default property to one with a custom setter, and it won't break code that uses it.

Tenfour04
  • 83,111
  • 11
  • 94
  • 154