I need to understand if a transient variable inside a class that implements Parcelable interface should be read from the parcel in modelClass(Parcel parcel) method or written to the parcel in writeToParcel(Parcel parcel,int i) . Can anyone provide me with a class implementation with a transient variable in it. Thank you.
The "transient"-keyword has no effect on parcelable objects. There is no automation in reading and writing the fields in a parcelable object, so there is no ready made code that would take it into account. Any possible choice of special processing for transient fields is completely up to the person designing the class.
Specification (https://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.3.1.3) says "Variables may be marked transient to indicate that they are not part of the persistent state of an object" so if you really want to go by the book you should not write them. But, as I said, since the reading and writing is done mechanically inside the class, the transient keyword doesn't make much sense.
class Employee implements Serializable {
private String firstName;
private String lastName;
private transient String confidentialInfo;
//Setters and Getters
}
You can simply add transient keyword before data type while declaring variable.
class Parcel implements Parcelable{
private Integer checkinId;
private transient String someCode;
//// some methods
}
interface Parcelable implements{
// some methods
}
Related
The below class doesn't have final keyword but its member variables are private and final and the class exposes no mutate/set methods. Is this class immutable or not?
public class Abc {
private final int id;
private final String name;
public Abc(int id, String name) {
this.id = id;
this.name = name;
}
public String getName() {
return name;
}
public int getId() {
return id;
}
}
The class itself is immutable, yes - if you create an instance of just Abc, no aspect of that can be changed after the instance has been created.
However, that doesn't mean that any code receiving a parameter of type Abc can assume it's immutable with all the benefits that carries... because the class isn't final. It's entirely possible for an object of a type compatible with Abc to be mutable:
public class Mutable extends Abc {
private String value;
public Mutable(int id, String name) {
super(id, name);
}
public void setValue(String value) {
this.value = value;
}
#Override public String toString() {
return value;
}
}
Now imagine you've got code which deals with an Abc:
public class AbcConsumer {
private final Abc abc;
public AbcConsumer(Abc abc) {
this.abc = abc;
}
// No need to create a defensive copy or anything like that...
// abc is immutable, right?
public Abc getAbc() {
return abc;
}
}
Here the consumer assumes it's fine to treat Abc as if it's an immutable class - but if someone creates an AbcConsumer by passing in a Mutable instance instead of "vanilla" Abc instance, it could cause problems.
That's why it's generally a good idea when you're creating an immutable type to make it final as well - that way any consumers know that if they receive a reference with that type, it's definitely immutable.
To put it another way: yes, the Abc class is immutable... but you can't assume that a reference with a compile-time type of Abc refers to an immutable object.
As presented, yes, the class is immutable.
The "final" keyword on a class declaration prevents it from being extended - it's not related to immutability (unless your variables are declared public or protected).
Edit; "not related" is a poor choice of words, please see Jon Skeet's answer below
No, it is most likely not.
A problem is terminology. What do you mean by class? If you mean this code, sure, it's immutable. But 'this code' is not something that is particularly relevant to the concept of immutability. That usually makes a lot more sense if we consider it: this type.
As in, is the type Abc immutable?
As in, given:
public void foo(Abc abc) { ... }
is it safe to assume that the received abc couldn't possibly change?
And then the answer is no. That is not safe to assume: The type Abc is mutable.
The reason is that someone could make this:
class SneakyAbc extends Abc {
private int id;
public void setId(int id) {
this.id = id;
}
public String getId() {
return id;
}
}
This is why immutable classes are virtually always made final, to fully guarantee it.
Depending on how fancy you want to paint with the brush of 'what does this term mean', if all methods of Abc are final, you can consider it immutable as well if you really want to: Whilst the class does not need to be immutable (a subclass can add a new non-final field and create getters and setters for this), all the stuff you can 'witness' from the Abc type, assuming you don't use reflection, do appear immutable.
Exactly what definition of immutable you go with would be required knowledge to delve any further.
Note that something like java.io.File has only final fields and is final, and yet, it has easily observable state that can be modified: just.. delete the file, and voila you can see it. You can pull similar stunts with an IdentityHashMap to create a faux but nevertheless very observable 'field'.
Thus, 'immutable' as a concept: Useful. As a boolean flag to bestow upon a certain type or some java source file: Not useful.
Records
Other Answers directly addressed your questions about immutability, class being marked final, and subclasses being mutable. I’ll add an alternative option to more briefly accomplish your goal of immutability: Records.
Java 16 brings the new records feature. If the main purpose of your class is to immutably and transparently carry data, define your class as a record. The compiler implicitly creates default constructor, getters, equals & hashCode, and toString.
A record is implicitly final, so no risk of a subclass becoming mutable.
Declare the properties in parentheses. By default, you need not put anything in the curly braces body of a record.
record Abc ( int id , String name ) {}
Instantiate like any other class.
Abc x = new Abc ( 42 , "Snuffleupagus" ) ;
The implicit getter methods are simply the property names. The JavaBeans-style get…/is… method naming is not used. (You could add such methods if required.)
System.out.println( x.name() ) ;
Snuffleupagus
It is mutable if its internal states can be changed after the class is created.
In your example, although there is no class final, the inside situations cannot be changed again because of final keyword. In this way, the class becomes immutable again
According to the OOP concepts, encapsulation is considered as defined private variables and public getter and setter methods.
Example:
public class Student {
private String name;
private int id;
public void setName(String name){
name = this.name;
}
public void setID(int Id){
id= this.id;
}
public String getName(){
return name;
}
public int getID(){
return id;
}
}
But if I wrote this code in the following way, could I say this class follows encapsulation concept ?
Because here, we return department name by using public method.
public class Student {
private department;
public String getDepartmentOfStudent(String name){
// write java code to get department name based on name from DB
return department;
}
}
Case II: If private variable department was not declared and just return value retrieved from DB, would we say that this class follows encapsulation?
But if I wrote this code in the following way, could I say this class follows encapsulation concept ?. Because here, we return department name by using public method.
=> Usually getter and setter are public. variables are private.
Case II : If private variable "department" was not declared and just return value retrieved from DB, would we say that this class follows encapsulation?.
=> Yes, its still encapsulation . It is not mandatory to have both getter and setter for every variable. So how you set data in variable, does not matter.
Encapsulation is defined as the wrapping up of data under a single
unit. It is the mechanism that binds together code and the data it
manipulates.Other way to think about encapsulation is, it is a
protective shield that prevents the data from being accessed by the
code outside this shield.
1 - Technically in encapsulation, the variables or data of a class is
hidden from any other class and can be accessed only through any
member function of own class in which they are declared.
2 - As in encapsulation, the data in a class is hidden from other classes, so it is also known as data-hiding.
3 - Encapsulation can be achieved by: Declaring all the variables in the class as private and writing public methods in the class to set
and get the values of variables.
Source:- https://www.geeksforgeeks.org/encapsulation-in-java/
For both cases, the answer is also "Yes". It is because your private field variable is not being accessed directly by other classes (e.g. declaring it as public String department). Accessible department is still being controlled by the code path of public String getDepartmentOfStudent(String name) which is playing the role of a public getter.
Getter gets it's names due to it's functionality that it returns some private attributes not by it's name. For example: getName() or getAge().
If a method named abc() returns some private data member/attribute then it is a getter method.
Yes your code follows encapsulation. In encapsulation the variables of the object cannot be directly accessed and modified by any other object.
In Case II:
If private variable "department" was not declared and there is no other public variables in your class, then yes you have encapsulation as the class's variables or data cannot directly accessed by another class.
To answer both questions we need take into account the concept of encapsulation
The localization of knowledge within a module. Because objects
encapsulate data and implementation, the user of an object can view
the object as a black box that provides services. Instance variables
and methods can be added, deleted, or changed, but as long as the
services provided by the object remain the same, code that uses the
object can continue to use it without being rewritten. (...)
So, we can say YES, it does; because to the client consuming the information provided by Student there is no knowledge of how the value of department is being retrieved/handled and returned, it just knows that from the call to getDepartmentOfStudent will be a String result. It actually doesn't care whether it is comming from database or memory, only Student knows that.
The main objective is to avoid duplication of fields with best inheritance model on existing stuff:
I have following class hierarchy:
class A
{
private String fieldA1;
private String fieldA2
// getters and setters
}
Class B extends A
{
private String fieldB1;
private String fieldB2;
// getters and setters
}
A 'User' class will either extend A or B having its own fields.
Assume existing API's uses above data models.
Now there is a requirement to add new fields in Class A for new set of API's.
I have certain restriction not to modify existing data models since it exposes or breaks existing API's with these new fields . So new data models need to be created by extending existing ones such that new API's uses them with all existing fields + new fields. I have below solution which may not be the best approach as it adds duplication of fields.
class A
{
private String fieldA1;
private String fieldA2
// getters and setters
}
Class B extends A implements Common
{
private String fieldB1;
private String fieldB2;
// getters and setters
}
Class NewA extends A
{
private String fieldNewA;
// getters and setters
}
Class NewB extends NewA implements Common
{
private String fieldB1;
private String fieldB2;
private String fieldNewB;
// getters and setters
}
Interface Common
{
//marker interface
}
Please suggest if there is any better approach.
Thanks...
I think you need to take a step back and look at what is it that is causing you to keep adding new fields to your existing classes. Maybe you should just have one field which is a collection of property and values. This way any new field will just be another property/value in your collection. You won't have to then worry about adding new fields frequently.
Your example is not great, for example sub-classes cannot access private fields and it is not clear what you intend your subclasses to achieve.
If you wish to inherit state, your example should use either protected or public fields, or show getter and setter methods being inherited. When inheriting state, implementing an interface like Common is redundant. More detail may help clarify your intent.
That aside, yes you can extend your data models as you describe in order to add data types to an existing class. An example of wanting to do this might be wishing to create a Square class from a Triangle class, requiring adding a new point. And also requiring changing behaviour to make use of the new field.
Suppose i have a class A:
class A
{
private String value;
private B field;
public C otherField;
}
class C
{
private String otherValue;
}
class B
{
private String name;
}
Now, if i do a A.class.getClasses(), ill get an array with one element (the one which is public, something that makes sense based on what javadoc of Class.java says).
My question is: is there a way to get return a list of public + private fields of a class?
Thanks
The getClasses() method is not the correct way to access the Fields that are part of the A class. You need to use the getDeclaredFields() method to access an array of Field objects representing the fields in the class. From there, you'll need to set the accessibility of the field to true with a call to setAccessible(). There is more information available by looking into the Java Reflection API as well as here
You should notice, that getDeclaredField will only return the fields of the class which are declared in the class. Fields which are inherited from a super class will not be returned. To get all fields of a class you have to iterate over the super classes (using Class.getSuperclass()).
I understand Enum is Serializable. Hence, it is safe to do so. (selectedCountry is enum Country)
Original enum without customer member variables
public enum Country {
Australia,
Austria,
UnitedState;
}
Fragment
#Override
public void onActivityCreated (Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (savedInstanceState != null) {
selectedCountry = (Country)savedInstanceState.getSerializable(SELECTED_COUNTRY_KEY);
}
}
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
savedInstanceState.putSerializable(SELECTED_COUNTRY_KEY, selectedCountry);
}
However, what if I have non-serializable members in custom enum class? For instance,
Original enum customer member variables
package org.yccheok;
import org.yccheok.R;
/**
*
* #author yccheok
*/
public enum Country {
Australia(R.drawable.flag_au),
Austria(R.drawable.flag_at),
UnitedState(R.drawable.flag_us);
Country(int icon) {
this.icon = icon;
nonSerializableClass = new NonSerializableClass(this.toString());
}
public int getIcon() {
return icon;
}
public static class NonSerializableClass {
public NonSerializableClass(String dummy) { this.dummy = dummy; }
public String dummy;
}
private final int icon;
public NonSerializableClass nonSerializableClass;
}
I tested. It works. (I tested by printing out all the value of member variables before and after serialization. They are same before and after)
However, I do not understand why it works? As I do not provide proper readObject and writeObject, as required by Serializable interface.
As pointed in Effective Java Item 75: Consider using a custom serialized form, do I need to provide my own readObject and writeObject, if I have custom member variables in my enum?
The reason it works is that serialization process for Enum's is different from serialization process for other classes. From the official documentation:
1.12 Serialization of Enum Constants
Enum constants are serialized differently than ordinary serializable or externalizable objects. The serialized form of an enum constant consists solely of its name; field values of the constant are not present in the form. To serialize an enum constant, ObjectOutputStream writes the value returned by the enum constant's name method. To deserialize an enum constant, ObjectInputStream reads the constant name from the stream; the deserialized constant is then obtained by calling the java.lang.Enum.valueOf method, passing the constant's enum type along with the received constant name as arguments. Like other serializable or externalizable objects, enum constants can function as the targets of back references appearing subsequently in the serialization stream.
That means, all your custom fields won't be serialized. In your case everything works well because your application process is still running and you are getting the same Enum instance that you passed to savedInstanceState.putSerializable.
But imagine a situation where your app get killed because Android has not enough memory. The next time user opens the app you will get a new Enum instance and all custom fields will have been lost and reinitialized by the constructor. Thus, mutable fields in an enum are always effectively transient.
As per Serializable documentation, readObject and writeObject are not needed at all, so your question might be not fully correct.
Serializable is a marker interface and doesn't have any methods.
I refer you to this answer which provides additional details about the Serialization implementation (which explains why you don't necessary need write and read functions).
And, as mentioned here by Dianne Hackborn, Parcelable is much more efficient for Android.
If you're particularly interested in Enum, refer to below paragraph:
1.12 Serialization of Enum Constants
Enum constants are serialized differently than ordinary serializable or externalizable objects. The serialized form of an enum
constant consists solely of its name; field values of the constant are
not present in the form. To serialize an enum constant,
ObjectOutputStream writes the value returned by the enum constant's
name method. To deserialize an enum constant, ObjectInputStream reads
the constant name from the stream; the deserialized constant is then
obtained by calling the java.lang.Enum.valueOf method, passing the
constant's enum type along with the received constant name as
arguments. Like other serializable or externalizable objects, enum
constants can function as the targets of back references appearing
subsequently in the serialization stream.
The process by which enum constants are serialized cannot be customized: any class-specific writeObject, readObject,
readObjectNoData, writeReplace, and readResolve methods defined by
enum types are ignored during serialization and deserialization.
Similarly, any serialPersistentFields or serialVersionUID field
declarations are also ignored--all enum types have a fixed
serialVersionUID of 0L. Documenting serializable fields and data for
enum types is unnecessary, since there is no variation in the type of
data sent.
So, I don't think that the Enum is the right choice to test internal non-serializable classes work.
The serialization of enum members is not working.
The nonSerializable field is never serialized as #vmironov answered. Here is a test:
public enum Country {
Australia;
public static class NonSerializableClass {
public NonSerializableClass() {}
public String dummy;
}
public NonSerializableClass nonSerializableClass;
}
The code writing the enum to the serialization stream:
public class SerializationTestWrite {
public static void main(String[] args) throws Exception{
FileOutputStream f = new FileOutputStream("tmp");
ObjectOutput s = new ObjectOutputStream(f);
Country.Australia.nonSerializableClass = new Country.NonSerializableClass();
Country.Australia.nonSerializableClass.dummy = "abc";
s.writeObject(Country.Australia);
s.flush();
System.out.println(Country.Australia.nonSerializableClass.dummy);
}
}
On writing the value of the dummy field is: abc
The code reading the enum from the serialization stream:
public class SerializationTestRead {
public static void main(String[] args) throws Exception{
FileInputStream in = new FileInputStream("tmp");
ObjectInputStream so = new ObjectInputStream(in);
Country readed = (Country) so.readObject();
System.out.println(readed.nonSerializableClass);
}
}
But on reading, the value of the field nonSerializableClass is: null