I have class Solution, that contains inner class A, class B, class C.
Class B extends class A, class C extends class B.
I want class C to be Serializable, so I implements Serializable in class C and in class Solution (class C is inner class of class Solution).
Because class C extends class B and class B extends class A, I create a no-arg constructor in class B and class A (I don't want them implements Serializable).
So the following code:
public class Solution implements Serializable {
public class A {
String name = "A";
public A(String name) {
this.name += name;
}
public A() {}
}
public class B extends A {
String name = "B";
public B(String name) {
super(name);
this.name += name;
}
public B() {}
}
public class C extends B implements Serializable {
String name;
public C(String name) {
super(name);
this.name = name;
}
}
}
public class Test {
public static void main(String[] args) throws IOException, ClassNotFoundException {
Solution.C c = new Solution().new C("C");
System.out.println(c.name);
System.out.println("serialization");
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("D:\\1.txt"));
oos.writeObject(c);
oos.close();
System.out.println("deserialization");
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("D:\\1.txt"));
Solution.C c1 = (Solution.C) ois.readObject();
ois.close();
System.out.println(c1.name);
}
}
throws the following exception:
C
serialization
deserialization
Exception in thread "main" java.io.InvalidClassException: Test3.Solution$C; no valid constructor
What happens in your case is that the deserialization code is eventually going to construct an instance of ObjectStreamClass for your class Solution.C. In the constructor of this class, it tries to find a constructor of the class to deserialize that is suitable. In your case, it will call ReflectionFactory#newConstructorForSerialization. Here's what the documentation of this method says:
Returns a constructor that allocates an instance of cl and that then initializes the instance by calling the no-arg constructor of its first non-serializable superclass. This is specified in the Serialization Specification, section 3.1, in step 11 of the deserialization process. If cl is not serializable, returns cl's no-arg constructor. If no accessible constructor is found, or if the class hierarchy is somehow malformed (e.g., a serializable class has no superclass), null is returned.
Your first non-serializable superclass is B, however B has no no-arg constructor because all its constructors have a synthetic parameter of type Solution. Thus, no constructor is found and deserialization fails. When you make B and A serializable, it works because newConstructorForSerialization will go up to Object (see loop below) and use its no-arg constructor.
public final Constructor<?> newConstructorForSerialization(Class<?> cl) {
Class<?> initCl = cl;
while (Serializable.class.isAssignableFrom(initCl)) {
Class<?> prev = initCl;
if ((initCl = initCl.getSuperclass()) == null ||
(!disableSerialConstructorChecks && !superHasAccessibleConstructor(prev))) {
return null;
}
}
Constructor<?> constructorToCall;
try {
constructorToCall = initCl.getDeclaredConstructor();
int mods = constructorToCall.getModifiers();
if ((mods & Modifier.PRIVATE) != 0 ||
((mods & (Modifier.PUBLIC | Modifier.PROTECTED)) == 0 &&
!packageEquals(cl, initCl))) {
return null;
}
} catch (NoSuchMethodException ex) {
return null;
}
return generateConstructor(cl, constructorToCall);
}
Can you just avoid doing this altogether? Reading the answers to this question, it seems strongly discouraged to serialized inner instances like you're doing now (full explanation in the link). You're giving yourself a hard time trying to do this, but at least now we know why this was failing.
Default constructor for parent classes are not required. Making class A as serializable it will work. You may also remove the serialization from class C.
public class Solution implements Serializable {
public class A implements Serializable{
String name = "A";
public A(String name) {
this.name += name;
}
public A() {}
}
public class B extends A {
String name = "B";
public B(String name) {
super(name);
this.name += name;
}
public B() {}
}
public class C extends B {
String name;
public C(String name) {
super(name);
this.name = name;
}
}
}
Related
I'm a beginner at Java so I don't know if what I'm trying to access is an upper/wrapper class. Basically, I have three classes, A, B and C.
CLASS A.java
public class A{
private String aName;
private B objectB;
}
CLASS B.java
public class B{
private String bName;
private C objectC;
}
CLASS C.java
public class C{
private String cName;
}
Basically, I have a Class A, which has an object of Class B, which in turn has an Object of class C.
I have an instance of an object of class C. How do I access the variables bName and cName from this instane of object C?
Why don't you use getter & setter method for accessing variable bName from instance of c. you can not directly access them as they are private.
"CLASS B.java"
public class B{
private String bName;
public String getbName() {
return bName;
}
public void setbName(String bName) {
this.bName = bName;
}
private C objectC;
}
You can directly access "cName" variable as this variable is the belong to same obejct of c which you are using to get bName.
The easiest solution for getting access to the instance of Class B from Class C would be to add a reference to B in C:
Class C
public class C {
private String cName;
private B bObj;
}
And then use getters and setters in class B:
Class B
public class B {
private String bName;
private C cObj;
public String getBName() {
return bName;
}
public void setBName(String newName) {
this.bName = newName;
}
}
However, do remember that this leads to a circular dependency, which usually is a code smell (it may be OK in this situation though, depending on the overall class hierarchy).
The better option would be to implement the Observer pattern between the classes:
Class C
public class C {
private String cName;
private List<Observers> observers; //if you only need one instance, then
//switch out for a single interface reference
public void requestWrapperName () {
List<String> names = new ArrayList<>();
for(observer: observers) {
names.add(observer.requestName());
}
// code to do what you want with wrapper name
...
}
public void addObserver(Observer observer) {
observers.add(obsersver);
}
}
Observer interface
public interface Observer {
String requestName();
}
Class B
public class B implements Observer {
private String bName;
private C cObj;
// Observer method
public String requestName() {
return bName;
}
}
Now, when you have the instance of C in class B, you can just inject B as an observer into C with cObj.addObserver(this); and then request B's name with the method requestWrapperName();. Thus avoiding having associations both ways :)
If i want to clone an object in java. So i have to implement Cloneable interface. But in case if that class is a subclass of another class than did i have to also mark(i.e. implement) the parent class as Cloneable.
Is this works?
public class A{
private String a;
public A(String a){
this.a = a;
}
}
public class B extends A implements Cloneable{
private String b;
public B(String a, String b){
super(a);
this.b = b;
}
public static void main(String args[]){
B b1 = new B("a","b");
B b2 = b1.clone();
}
}
NO,not needed you are cloning class B which is independent class and
class B just inheriting the properties of class A.
So it has nothing to do with the object class B object clone.
Try it and check it will work
It is not required by Parent class to implement Cloneable to make Subclass eligible for cloning.
Any subclass can simply implements Cloneable and override clone method to be eligible for cloning.
package com.pradeep.java.practise.object;
class A{
private String name;
public A() {
System.out.println("===A()===");
}
public A(String name){
System.out.println("===A(-)===");
this.name = name;
}
#Override
public String toString() {
return "A [name=" + name + "]";
}
}
class B extends A implements Cloneable{
private String name;
public B() {
System.out.println("===B()===");
}
public B(String name){
System.out.println("===B(-)===");
this.name = name;
}
#Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
#Override
public String toString() {
return "B [name=" + name + "]";
}
}
public class SubclassCloneTest {
public static void main(String[] args) throws CloneNotSupportedException {
B b = new B("sub class");
B clonedB = (B) b.clone();
System.out.println("original B = "+b);
System.out.println("cloned B = "+clonedB);
}
}
Output :
===A()===
===B(-)===
original B = B [name=sub class]
cloned B = B [name=sub class]
I have three classes.
Class A extends jFrame (Which is the main user interface)
Class B extends jPanel (This one is called to appear inside of the main jFrame)
and Class C to do some file handling and processing.
What I am trying to do is have an object of Class C instantiated in Class A and calling it in Class B.
Here's some sample code:
Public Class A extends javax.swing.JFrame {
Public A(){
C ObjectOfC = new C();
B panelWithButtons = new B();
}
}
public Class B extends javax.swing.JPanel{
String s = ObjectOfC.getName();
}
public Class C{
String name;
public String getName(){
return this.name;
}
}
Is there anyway to get this done? or is it a lost cause?
There are a number of ways to do this, depending on what you are trying to accomplish. You probably want to build either a constructor or a method for B that takes object C as an argument.
Example:
Public Class A extends javax.swing.JFrame {
Public A(){
C objectOfC = new C();
B panelWithButtons = new B(objectOfC);
}
}
public Class B extends javax.swing.JPanel{
String s;
public B (C objectOfC) {
this.s = objectOfC.getName();
}
}
public Class C{
String name;
public String getName(){
return this.name;
}
}
A singleton example as per your comment:
Public Class A extends javax.swing.JFrame {
Public A(){
B panelWithButtons = new B();
}
}
public Class B extends javax.swing.JPanel{
String s;
objectOfC C = C.getInstance();
this.s = objectOfC.getName();
}
public class C {
private static String name;
private static final C INSTANCE = new C();
private C() {}
public static C getInstance() {
return INSTANCE;
}
public static String getName() {
return this.name;
}
}
A singleton example with changing variables (and errors removed from the original code.):
public class A extends javax.swing.JFrame {
public A() {
C objectOfC = C.getInstance();
objectOfC.setName("Bob");
B panelWithButtons = new B(objectOfC);
System.out.println("objectOfC_A:" + objectOfC.getName()); //return "George"
}
}
public class B extends javax.swing.JPanel {
public B (C objectOfC) {
C c2 = C.getInstance();
objectOfC.setName("Fred");
c2.setName("George");
System.out.println("objectOfC_B:" + objectOfC.getName()); //returns "George"
System.out.println("c2: " + c2.getName()); //returns "George"
}
}
public class C {
private static String name;
private static final C INSTANCE = new C();
private C() {}
public static C getInstance() {
return INSTANCE;
}
public String getName() {
return C.name;
}
public void setName (String name) {
C.name = name;
}
}
With this example you can call C.getInstance from any class and they will all be sharing the same instance. However, you must be careful with how you are going to access the object; there are plenty of tutorials out there about multithreading singletons which you will need to do if you plan on modifying data in the C instance from multiple objects at the same time.
In java serialization class Mp3player extends ElectronicDevice implements Serializable in this code super class electronicdevice is not implemented serializable. here super class is also getting serialized. my understanding is super class is also gets serialized due to extends.let me know my understanding is correct or not.
import java.io.*;
class ElectronicDevice {
ElectronicDevice()
{
System.out.print("ed ");
}
}
class Mp3player extends ElectronicDevice implements Serializable {
Mp3player()
{
System.out.print("mp ");
}
}
class MiniPlayer extends Mp3player {
MiniPlayer()
{
System.out.print("mini ");
}
public static void main(String[] args) {
MiniPlayer m = new MiniPlayer();
try {
FileOutputStream fos = new FileOutputStream("dev.txt");
ObjectOutputStream os = new ObjectOutputStream(fos);
os.writeObject(m); os.close();
FileInputStream fis = new FileInputStream("dev.txt");
ObjectInputStream is = new ObjectInputStream(fis);
MiniPlayer m2 = (MiniPlayer) is.readObject();
is.close();
System.out.println();
} catch (Exception x) {
System.out.print("x ");
}
}
}
No.During the process of serialization only the fields of Serializable objects are written out and restored.
According to javadocs
During deserialization, the fields of non-serializable classes will be initialized using the public or protected no-arg constructor of the class.
Where as the fields of serializable subclasses will be restored from the stream.
Please look into this example
Here ElectronicDevice is not Serializable,where as Mp3player is Serializable.Observe the fields of respected classes behaviour in serialization process.
import java.io.*;
class ElectronicDevice {
public int i = 0;
protected ElectronicDevice()
{
System.out.println("ed ");
}
}
class Mp3player extends ElectronicDevice implements Serializable {
int j =0;
Mp3player()
{
System.out.println("mp ");
}
}
class MiniPlayer extends Mp3player {
MiniPlayer()
{
System.out.println("mini ");
}
public static void main(String[] args) {
MiniPlayer m = new MiniPlayer();
m.i = 30;
m.j = 40;
try {
System.out.println("i value before serialization: "+m.i);//prints 30
System.out.println("i value before serialization: "+m.j);//prints 40
FileOutputStream fos = new FileOutputStream("dev.txt");
ObjectOutputStream os = new ObjectOutputStream(fos);
os.writeObject(m); os.close();
FileInputStream fis = new FileInputStream("dev.txt");
ObjectInputStream is = new ObjectInputStream(fis);
MiniPlayer m2 = (MiniPlayer) is.readObject();
is.close();
System.out.println("i value after serialization: "+m2.i);//prints o
System.out.println("j value after serialization: "+m2.j);//prints 40
System.out.println();
} catch (Exception x) {
x.printStackTrace();
System.out.print("x ");
}
}
}
Since super class doesn't implement Serializable contents of the super class wont get serialized. Only the contents of the subclass would get serialized. When you deserialize the default constructor of the superclass would get executed and the fields of the superclass initialized as if you invoked the default constructor.
Following example illustrates this.
public class SerializationTest {
public static class Base {
private String name;
public Base() {
this.name = "johnDow";
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public static class Sub extends Base implements Serializable {
private static final long serialVersionUID = 1L;
private String age;
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
}
public static void main(String[] args) throws Exception {
ByteArrayOutputStream byteArrayOS = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(byteArrayOS);
Sub s = new Sub();
s.setName("name");
s.setAge("10");
out.writeObject(s);
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(byteArrayOS.toByteArray()));
Sub d = (Sub) ois.readObject();
System.out.println(d.getName() + "-" + d.getAge());
}
}
What gets printed is
johnDow-10
This is the rule for superclass serialization:
If you are a serializable class, but your superclass is NOT
serializable, then any instance variables you INHERIT from that
superclass will be reset to the values they were given during the
original construction of the object. This is because the
nonserializable class constructor WILL run.
Therefore, if you add some instance variables to ElectronicDevice, be aware that the superclass 's state will be not serialized. (unless the superclass implements Serializable)
my understanding is super class is also gets serialized due to
extends.let me know my understanding is correct or not.
The short answer is NO.
In java, every class is a subclass of Object. Does Object itself implement Serializable?
To allow subtypes of non-serializable classes to be serialized, the subtype may assume responsibility for saving and restoring the state of the supertype's public, protected, and (if accessible) package fields”
Reference -
http://docs.oracle.com/javase/7/docs/api/java/io/Serializable.html
I need to override toString() method for all of the concrete method of my abstract class - exactly the same in all cases. So here is what I want to do (SomeEnum is a separate class which has just an enum declaration):
abstract class
public abstract class ClassA {
protected SomeEnum name;
protected int some_int;
// Constructor here
#Override
public String toString() {
return name.toString().toLowerCase() + " > " + Integer.toString(some_int);
}
}
concrete class (example)
public class ClassB extends ClassA {
private static final int some_const = 1;
private SomeEnum name = SomeEnum.ENUM_1;
public ClassB(int some_int) {
super(some_const, some_int);
}
}
For some reason I cannot do it that way without runtime exceptions and I need to declare abstract method in the abstract class and then provide (exactly the same) implementation of toString() in every of the concrete classes implementations.
What is wrong with this approach?
EDIT: The exception I get is NullPointerException that then points me to ClassA.toString().
Instead of declaring name as a field on ClassB assign someEnum in the constructor of ClassB so it uses the field from the supertype. The supertype does not have access to the name field on the subtype, which causes the NPE when toString is called.
public ClassB(int some_int) {
super(some_const, some_int);
this.name = SomeEnum.ENUM_1;
}
Full Example
ClassB
public class ClassB extends ClassA {
private static final int some_const = 1;
public ClassB(int some_int) {
super(some_const, some_int);
this.name = SomeEnum.ENUM_1;
}
public static void main(String[] args) {
ClassB b = new ClassB(4);
b.toString();
}
}
ClassA
public abstract class ClassA {
protected SomeEnum name;
protected int some_int;
public ClassA(int someConst, int some_int2) {
}
#Override
public String toString() {
return name.toString().toLowerCase() + " > "
+ Integer.toString(some_int);
}
}