java, initialize SubClass from SuperClass - java

public class Base {
//long list of attributes
// no Constructor using fields
// no init methode
// i cannot change this class
}
now i extended the Base Class like:
public class subClass extends Base{
private boolean selected;
...
getter und setter
...
}
i become a list of Base object List<Base>
but i need the same list but as List<SubClass>
is there a way to initialize the Subclass from the Base Class?
example:
for(Base b: list){
SubClass sub = (SubClass)b; // Thats wrong i know
if(...){
sub.setSelected(true);
}
newList.add(sub);
}
i try to avoid the manual init of each Attribute of the Base Class to the SubClass
i update my Question as requested in the Comments:
the Design above is just an example. my QUESTIN EXACTLY IS:
why converting BaseClass into SubClass (sence Subclass extends BaseClass) is not Possible? why Java dosn't allow me to do the following:
example:
Class Base{
private String name;
.....
}
Class SubClass extends Base{
private String title;
}
then
Base b = DBController.getById(...);
SubClass sub = (SubClass)b;
after that the Object sub should have the Attribute Name from the Object b
and the title Attribute is null
why is this not the case in java?
sorry for my bad english,
thanks

If you have a List<Base>, then you cannot convert it to a List<SubClass>. This is mainly because the list may not contain instances of SubClass. The best you can do is:
List<SubClass> newList = new List<SubClass>();
for(Base b: list){
if (b instanceof SubClass) {
SubClass sub = (SubClass)b;
. . .
newList.add(sub);
}
}
Generally, however, when you find yourself doing this kind of thing, there's something wrong with your design. You might want to avoid subclassing Base and using composition instead.
EDIT Based on your comments, it sounds like you want to construct a list of SubClass instances using a list of Base instances as a start. One approach is to define a constructor for SubClass that takes a Base as an argument.
public class SubClass extends Base{
private boolean selected;
public SubClass() {
// default constructor
}
public SubClass(Base original) {
// copy constructor -- initialize some fields from
// values in original, others with default values
}
...
getter und setter
...
}
Then you can construct your new list with:
List<SubClass> newList = new List<SubClass>();
for(Base b: list){
SubClass sub = new SubClass(b);
. . .
newList.add(sub);
}

There is a way: Various Java Beans spec based manipulation.
For example:
Commons BeanUtils
for( Base base: list ){
SubClass sub = new SubClass();
PropertyUtilsBean.copyProperties( sub, base );
if(...){
sub.setSelected(true);
}
newList.add(sub);
}
This works based on get/setters of the same name. Doesn't copy internal fields.
If you needed to copy internal fields, it's actually not that hard to implement using javax.lang.reflect.

You appear to have a class with a lot of attributes and no easy way of setting them all. You have now run in to a problem where you need a class with an additional attribute but you have to deal with that mess of a base class.
I suggest that, instead of creating a subclass and casting, you create a wrapper class around the ugly one:
public class BigDumbClass {
// A lot of attributes
// No Constructor
// No init method
}
public class Wrapper {
private BigDumbClass base;
private boolean selected;
public Wrapper(BigDumbClass base) {
this.base = base;
this.selected = false;
}
//getters and setters
}
Now when you have to create that new list you can wrap everything in the old list
List<BigDumbClass> oldList = someData();
List<Wrapper> wraps = aNewList();
for (BigDumbClass bigDumb : oldList) {
Wrapper wrap = new Wrapper(bigDumb);
if (someCondition()) {
wrap.setSelected(true);
}
wraps.add(wrap);
}
Ideally, BigDumbClass would implement an interface that Wrapper could also implement, allowing the wrapper to defer all of the calls to the instance it has wrapped.
public class BigDumbClass implements SharedInterface {
// All the stuff outlined above
}
public class Wrapper implements SharedInterface {
// All the stuff outlined above
// Methods defined in SharedInterface
public void doSomething() {
base.doSomething();
}
}
Otherwise, you can provide a getter to the instance and access it directly.
BigDumbClass base = wrapper.getBase();
base.doSomething();

Related

How do I create a class out of a superclass without downcasting?

I'm using spring-data-neo4j and I have two node entities, Person and Owner extends Person
When I save person, it gets the label :Person, and when I save an owner, it gets the labels :Owner and :Person. Excellent. Exactly what I wanted.
Sometimes we have people that become owners, so I'd like to convert that person to an Owner and add the missing data (such as properties).
Obviously downcasting doesn't work. There is a way I've heard of where you can get a subclass to call its superclass with parameters. I'd like to avoid the adapter pattern as there will be hundreds of inherited fields from Person.
How do I "construct" an Owner from a Person?
/*** MAIN CLASS ***/
public class Application {
public static void main (String[] args) {
Person p = personRepository.findByEmail ("joesoap#example.com");
Owner o = new Owner(p); // Trying to construct a person from an owner
o.addProperty (...);
ownerRespository.save(o);
}
}
/*** PERSON ***/
#NodeEntity
public class Person {
public Person(Person person) {
this = person; // Obviously this won't work, but I can't think of the solution...
}
String fullName;
String email;
}
/*** OWNER ***/
#NodeEntity
public class Owner extends Person {
public Owner(Person person) {
super (person);
}
public List<Property> properties;
}
Java classes were never meant to handle cases where one wants to make an object of one type into another type. Obviously treating a subclass as its superclass, or treating a class as an object which implemented an interface, were intended, but Java just has no good way of converting an object of one class into an object of another class.
You could convert the object to XML and then read the superclass fields into the subclass; kind of a brute-force-leave-the-XML-in-memory approach.
But I think what you have is a problem where Owner should not be represented by a subclass, for the specific reason that you sometimes want to convert from one class to the other. I think your Person class should have a field of a type containing owner information, null if the person is not also an owner.
This is what you do when you need to clone an object. Unfortunately the only way is to set each property manually:
class Test {
private String prop1;
private String prop2;
public Test() {}
public Test(Test test) {
setProp1(test.getProp1());
setProp2(test.getProp2());
}
public String getProp1() {
return prop1;
}
public void setProp1(String prop1) {
this.prop1 = prop1;
}
public String getProp2() {
return prop2;
}
public void setProp2(String prop2) {
this.prop2 = prop2;
}
}
So in your case you call the cloning constructor, then setting the extra parameters in Owner
Downcasting is only allowed if there is a chance that it will succeed at runtime. In your case you would want to do as #arcy stated: add the extra parameters and initialize them as null if the person is not also an owner.
As mentioned in some other answers, creating a subclass instance from an instance of its superclass has its drawbacks, and has no direct support in Java. The resulting subclass instance is typically incomplete since it is only a clone of the superclass fields, and would then need additional field set-calls to populate subclass-specific fields. This might not be an issue in your application. Solving this through composition as suggested by #arcy is another decent option.
If you must create a subtype instance from a supertype instance, then copy-via-serialization is the best option. The key is to choose a flexible and high-performing serialization mechanism, and something better than native Java serialization. A library like Kryo is one decent option.
Using Kryo you could create a utility class to help register the serializers for the classes involved, then perform the clone-to-subclass-instance:
public class KryoDowncastCloneUtil {
private static final KryoDowncastCloneUtil instance = new KryoDowncastCloneUtil();
public static KryoDowncastCloneUtil instance() {
return instance;
}
private final Kryo kryo = new Kryo();
public <A, B extends A> void register(Class<A> superClass, Class<B> subClass) {
final Serializer<A> superClassSerializer = new FieldSerializer<>(kryo,
superClass);
// the superClass serializer is registered for both the superClass and its subClass
kryo.register(superClass, superClassSerializer);
kryo.register(subClass, superClassSerializer);
}
public <A, B extends A> B copyAndDowncast(A superClassInstance, Class<B> subClass) {
byte[] buffer = null;
try (final ByteArrayOutputStream stream = new ByteArrayOutputStream();
final Output output = new Output(stream)) {
kryo.writeObject(output, superClassInstance);
output.flush();
buffer = stream.toByteArray();
} catch (IOException e) {
// these are only from auto-close, swallow
} // auto-close stream, output
final B subClassInstanceClonedFromSuperClassInstance = kryo.readObject(new Input(
new ByteArrayInputStream(buffer)), subClass);
return subClassInstanceClonedFromSuperClassInstance;
}
}
The key here is that the same serializer, the one for the super-class A, is registered for serializing both the super-class and its sub-class B. This allows an instance of subclass B to be instantiated from the field data serialized from A - its own fields will be left null. You can then add some syntactic sugar to actual classes if desired:
public class Owner extends Person {
static {
KryoDowncastCloneUtil.instance().register(Person.class, Owner.class);
}
// ...
public static Owner fromPerson(Person person) {
return KryoDowncastCloneUtil.instance().copyAndDowncast(person, Owner.class);
}
}

How can I automatically put subclasses in an ArrayList?

I have a superclass, and then several subclasses, like this:
public abstract class A {
public abstract int getValue();
}
public class B extends A {
public int getValue() {
return 1;
}
}
public class C extends A {
public int getValue() {
return 123;
}
}
public class D extends A {
public int getValue() {
return 15234;
}
}
There are about 100 or so subclasses. I also have a manager:
public class Manager {
public static ArrayList<A> list = new ArrayList<A>();
}
How can I "magically" add an instance of all subclasses of A to list without manually creating an instance of every single subclass and adding it to the list? Perhaps with using an Initialization Block?
EDIT
It's not important how I access list in Manager. I edited it to be static.
(2nd attempt - my first attempt was based on a misunderstanding of the Question.)
I'm assuming that what you want to do is build a (static) list that:
contains exactly one instance of each of the subclasses,
is created and populated ahead of time, and
doesn't involve code in each subclass creating / adding an instance of itself to the list.
Firstly, an instance initializer block won't do this. An instance initializer is run when you create an instance ... and something has to new the class (i.e. each of the subclasses) for this to happen.
I think the only viable approach is to write some hairy reflective code that:
iterates over all classes on the classpath,
loads each one using Class.forName(),
reflectively tests to see if the class is a subclass of A,
if it is, reflectively invokes the classes no-args constructor and adds the resulting instance to "the list".
This is (IMO) pretty hacky!! And it is going to be expensive ... unless you can limit the "package space" that needs to be searched for these subclasses.
Actually, this could be a problem that would be better solved using an enum ... especially if the subclasses don't have behavioural differences that require different method implementations. (For instance your getValue() method could just return a private variable ... that you initialize using a constructor.) See #Paul Bellora's answer.
(The thing that would prevent this from being applicable would be if there needed to be multiple instances of some of the subclasses. That's not possible with enums.)
Each class is going to represent a command.
Based on the description of your problem, it sounds like A could be an enum:
public enum A {
B(1) {
#Override
public void execute() {
//code and stuff
}
},
C(123) {
#Override
public void execute() {
//code and stuff
}
},
D(15234) {
#Override
public void execute() {
//code and stuff
}
};
private final int value;
private A(int value) {
this.value = value;
}
public int getValue() {
return value;
}
public abstract void execute();
}
Now, there is exactly one instance of each command, and you can easily iterate commands with A.values().
Although it doesn't quite make sense... one way you can do is, do things similar to Spring's component scanning: make use of things like PathMatchingResourcePatternResolver and find out all possible classes. Iterate through them and add to list if that is a subclass of A.
This is a bit of a hackish way to do it, but if all your subclasses are in one folder (the actual class files) you could iterate over the files in the folder and use the ClassLoader. You code would look something along the lines of -
for(String className : classNames){
Class clazz = classLoader.loadClass(className);
list.add(clazz.newInstance());
}
Look at the ClassLoader API for more info. Also keep in mind that this is not very efficient, but if you are just doing this once you should be fine.
Could be like this :
public abstract class A {
public A(Manager m) {
m.list.add(this);
}
public abstract int getValue();
}
public class B extends A {
public B(Manager m) {
super(m);
}
}
This way you never again have to deal with m.list.add(new A()); while subclassing. But I don't know if this is what you are looking for...
EDIT :
It's not important how I access list in Manager. I edited it to be static.
If you don't care about using singletons, here is a very basic implementation:
But read What is bad about singletons.
public class Manager {
private static Manager instance = null;
protected Manager() {
// Exists only to defeat instantiation.
}
public static Manager getInstance() {
if(instance == null) {
instance = new Manager();
}
return instance;
}
}
Then:
public abstract class A {
public A() {
Manager.getInstance().list.add(this);
}
public abstract int getValue();
}
public class B extends A {
}
But, again this is very not satisfying as a design...
1) You need to find all available subclasses of class A. For that you need to scan all classes on the Java classpath. To make things easier we can assume that all subclasses are in the same location as A.class. A is supposed to be in a jar or in a folder. We can find out its actual location as
URL url = A.class.getProtectionDomain().getCodeSource().getLocation();
2) Lets assume that it is a folder, eg file:/D:/workspace1/x/target/classes/. Now we should walk thru all .class files in this folder and subfolders. We can use File.listFiles or Java 7 NIO2 for that. We have 2 options
a) load each class and check its superclass
Class cls = Class.forName();
if (cls.getSuperClass() == A.class) {
...
b) use javaassist framework http://www.javassist.org or similar to work with class file directly
DataInputStream ds = new DataInputStream(new BufferedInputStream(path));
ClassFile cf = new ClassFile(ds);
String superClass = cf.getSuperClass();
if (superClass.equals("A")) {
Class cls = Class.forName(cf.getName());
...
option b is loads only the classes you actually need, option a is simpler but it loads all classes in the folder
In both cases you create of an instance as
A a = (A) cls.newInstance();
assuming that all subclasses have no-arg constructor
How about using a class path scanner to automatically detect your target classes :
List<Class<?>> classes = CPScanner.scanClasses(new ClassFilter().packageName("com.foo.*").superClass(A.class));
Since you've got the target classes, you can easily initialize them by using newInstance method.
By the way use the maven dependency below to use the given snippet:
<dependency>
<groupId>net.sf.corn</groupId>
<artifactId>corn-cps</artifactId>
<version>1.1.1</version>
</dependency>
Cheers.

Java transferring variables from a super class to the sub class

In java i have a class A which extends class B
I want to assign all of the contents from class B to class A
thing is i want to do it from inside class A now this seems reasonable easy to do just transfer all of the variables.
This is the hard part. I didn't make class B it's a part of android.widget
In c++ you would just take in class b and then assign to *this and cast it.
How would i go about doing this in java?
To further clarify it's a relativelayout i need to copy all the contents of a relativelayout into a class that extends relative layout
class something extends other
{
public something(other a){
//transfer all of the other class into something
this=(something)a; // obviously doesn't work
//*this doesn't exist?
//too many variables to transfer manually
}
}
Thanks so much for all the help. Really appreciate it!!!
See the code given below . It is using java.lang.reflect package to extract out all the fields from super class and assigning the obtained value to the child class variables.
import java.lang.reflect.Field;
class Super
{
public int a ;
public String name;
Super(){}
Super(int a, String name)
{
this.a = a;
this.name = name;
}
}
class Child extends Super
{
public Child(Super other)
{
try{
Class clazz = Super.class;
Field[] fields = clazz.getFields();//Gives all declared public fields and inherited public fields of Super class
for ( Field field : fields )
{
Class type = field.getType();
Object obj = field.get(other);
this.getClass().getField(field.getName()).set(this,obj);
}
}catch(Exception ex){ex.printStackTrace();}
}
public static void main(String st[])
{
Super ss = new Super(19,"Michael");
Child ch = new Child(ss);
System.out.println("ch.a="+ch.a+" , ch.name="+ch.name);
}
}
All the variable and function of parent class(not private) is direct access in child class.You don't need to assign any thing in child Class.You can direct access.
This will not work:
Something something = (Something) other.clone();
if the true runtime type of other is Other.
Instead you have to create a copy constructor, or instantiate other as an instance of Something and then clone it.

Subinstances sharing a common superinstance

I have a class Super and several subclases Sub1, Sub2,...
Is there a way to instantiate objects sub1, sub2 that would share the same super instance?
The situation comes from an inner nested class configuration like this:
Super{
superFields...
Sub1{...}
Sub2{...}
........
}
But the inner claeses have grown too much, and I woud feel more confortable having them in separate files. They need to share the same instance of superFields, so my question.
Inner classes are implemented by having the superclass as argument of all their constructors.
So that's what you can do as well:
public class Sub1 {
private Superclass superclass;
public Sub1(Superclass superclass) {
this.superclass = superclass;
}
}
and whenever you want to instantiate the subclass from within the superclass:
Sub1 sub = new Sub1(this);
You could easily break out your inner classes and have each of them reference an instance of the current containing class. When you construct your new classes, you can pass in the same instance to both, and then the new classes can use the accessors to get at the fields of the containing class.
class Super {
String fieldA;
int fieldB;
...
}
in your new files, something like the following:
class Sub1{
Super myOldContainingClass;
Sub1(Super myOldContainingClass) {
this.myOldContainingClass = myOldContainingClass;
}
void myMethod() {
System.out.println(myOldContainingClass.getFieldA());
System.out.println(myOldContainingClass.getFieldB());
}
}

Overriding a super class's instance variables

Why are we not able to override an instance variable of a super class in a subclass?
He perhaps meant to try and override the value used to initialize the variable.
For example,
Instead of this (which is illegal)
public abstract class A {
String help = "**no help defined -- somebody should change that***";
// ...
}
// ...
public class B extends A {
// ILLEGAL
#Override
String help = "some fancy help message for B";
// ...
}
One should do
public abstract class A {
public String getHelp() {
return "**no help defined -- somebody should change that***";
}
// ...
}
// ...
public class B extends A {
#Override
public String getHelp() {
return "some fancy help message for B";
// ...
}
Because if you changed the implementation of a data member it would quite possibly break the superclass (imagine changing a superclass's data member from a float to a String).
Because you can only override behavior and not structure. Structure is set in stone once an object has been created and memory has been allocated for it. Of course this is usually true in statically typed languages.
Variables aren't accessed polymorphically. What would you want to do with this that you can't do with a protected variable? (Not that I encourage using non-private mutable variables at all, personally.)
class Dad{
public String name = "Dad";
}
class Son extends Dad{
public String name = "Son";
public String getName(){
return this.name;
}
}
From main() method if you call
new Son().getName();
will return "Son"
This is how you can override the variable of super class.
Do you mean with overriding you want to change the datatype for example?
What do you do with this expression
public class A {
protected int mIndex;
public void counter(){
mIndex++;
}
}
public class B extends A {
protected String mIndex; // Or what you mean with overloading
}
How do you want to change the mIndex++ expression without operator overloading or something like this.
If you have the need to override an instance variable, you are almost certainly inheriting from the worng class.
In some languages you can hide the instance variable by supplying a new one:
class A has variable V1 of type X;
class B inherits from A, but reintroduces V1 of type Y.
The methods of class A can still access the original V1. The methods of class B can access the new V1. And if they want to access the original, they can cast themself to class A (As you see dirty programming provokes more dirty progrtamming).
The best solution is to find another name for the variable.
you can override a method,that is all right
but what do you mean by overriding a variable?
if you want to use a variable at any other place rather than super class
u can use super.
as in
super(variable names);
why do you want to override a variable?
i mean is there any need?
we can not overriding structure of instance variables ,but we ovverride their behavior:-
class A
{
int x = 5;
}
class B extends A
{
int x = 7:
}
class Main
{
public static void main(String dh[])
{
A obj = new B();
System.out.println(obj.x);
}
}
in this case output is 5.

Categories

Resources