I am trying to write a set of User Interfaces that operate similarly for multiple classes, which all extend an abstract class Category: HouseCategory extends Category, CarCategory extends Category
Most of the code works fine just by using polymorphism, but there is one section where I need to create a new instance of the extended category
Obj foo = new HouseCategory(a, b, c)
How can I make this work for all subclasses of Category? - they all have the same constructor arguments. I don't know much about generics, but is it possible for me to have the UI class defined as
public class UserInterface <T extends Category> extends JFrame {
or possibly
public class UserInterface extends JFrame {
public UserInterface(Class<T extends Category> clazz) {
and build from there?
Help much appreciated.
EDIT: Also, is it possible to get a static field from the generic class?
I'd rather not have to have a statement checking "if (clazz instanceof HouseCategory) name = HouseCategory.NAME" as there may be hundreds of classes.
Introduce a new factory to create the category objects or the user interfaces. The factory needs to be extended whenever you add a new category, but that shouldn't be a big problem:
public class CategoryFactory {
public static enum Type {HOUSE, CAR}
public static Category createCategory(Type type, Param a, Param 2, Param b) {
if (type == null) return null;
switch(Type) {
case HOUSE: return new HouseCategory(a,b,c);
case CAR: return new CarCategory(a,b,c);
}
return null; // or throw exception -> tells, that a new enum is not handled yet
}
}
Then, if you protect the constructors in the category subclasses and keep those subclasses and the factory in one package, you can make it pretty difficult to bypass the factory.
Generics can't really help you with this due to type erasure. At runtime your code doesn't "know" the values of the type parameters.
One approach would be to use the factory pattern. Create a factory class for each Category and have these all implement a common factory interface (probably CategoryFactory). Then give factory objects to the UserInterface rather than Class objects.
Another approach would be to use reflection to invoke the constructor on the Class object. I'm not a fan of this approach as it throws compile time checking out the window, but it would involve using the getConstructor method on the Class.
Pass the class to the interface. Use reflection to invoke the constructor and access the NAME field. But it's better to employ instance methods that subclass can override:
/** subclass must have the default constructor */
abstract class Category
abstract void init(a, b, c);
abstract String name();
class HouseCategory extends Category
void init(a, b, c){ ... }
String name(){ return "House"; }
class UserInterface
UserInterface(clazz)
Category foo = (Category)clazz.newInstance();
foo.init(a,b,c);
String name = foo.name();
Related
Given
public class Foo {
public static class FooBuilder { ... }
}
I want to write a method on a third class that returns Foo, given Foo.FooBuilder.class
i.e.
Foo f = x.make(Foo.FooBuilder.class, someData);
Is it possible to declare a signature using generics that can imply the return type? Is there some language feature that lets me say "type U is outer class of type T"?
Obviously, it is possible to specify that type extends, or is the base of, a generic type (U extends T or U super T, respectively) but I am looking for U outer T which is, I think, more than Java can offer, even indirectly, at least in 1.7, which I am targeting.
So far, I have simply declared both inner and outer types, which works but is a wider definition than I am after and looks clumsy too.
public <TYPE,BUILDER> TYPE make(Class<BUILDER> builderClass, Map<String,Object> data) {
// Construct TYPE
}
Is there a way to infer TYPE without explicitly providing a template parameter?
There is a Class#getDeclaringClass method that may work in your case.
Quoting the docs:
If the class or interface represented by this Class object is a member of another class, returns the Class object representing the class in which it was declared.
EDIT:
After the clarification of OP, here is the new suggestion:
You create an generic interface to mark all your nested classes:
public interface Nested<P> {
}
Then you apply it to your Foo.Bar class like this:
public class Foo {
public static class Bar implements Nested<Foo> {
}
}
Then in your factory you can have the following:
public <P> P make(Class<? extends Nested<P>> clazz, Map<String, Object> someData) {
// do whatever you need to do
return (P) clazz.getDeclaringClass();
}
However, with this construct, there is not way to validate it your nested class is the real class, declared when implementing the generic interface.
I am new to Java and I have read threads (here) that it is not possible to instantiate an abstract class. So, I tested it out.
The first test I did is shown below. And it seems like I can actually instantiate an abstract class and in fact, I actually have a new type which refers to the abstract class and the type is actually shared by all subclasses the extends it. This also means polymorhpism applies.
import java.util.*;
abstract class AbstractClass{
public abstract void printname();
}
class Test1 extends AbstractClass{
private String name;
public Test1(String name){
this.name = name;
}
public void printname(){
System.out.println("My name is " + name);
}
}
class Test2 extends AbstractClass{
private String saysomething;
public Test2(String saysomething){
this.saysomething = saysomething;
}
public void printname(){
System.out.println(saysomething);
}
}
class TestingApp{
public static void main(String[] args){
AbstractClass[] abstractclass_list = {new Test1("JEFFFFFF") , new Test2("Hey , say something")};
for(AbstractClass item : abstractclass_list){
item.printname();
}
}
}
Then I did another test but this time, instead of working on abstract class, I decided to create a type which refers to Interface. It seems like I can instantiate an interface as well. I can actually create a type that refers to the interface. This type is shared by all the classes that implements this interface. And polymorphism applies again.
import java.util.*;
interface AbstractInterface{
public void printname();
}
class Test4 implements AbstractInterface{
private String name;
public Test4(String name){
this.name = name;
}
public void printname(){
System.out.println("My name is " + name);
}
}
class Test3 implements AbstractInterface{
private String saysomething;
public Test3(String saysomething){
this.saysomething = saysomething;
}
public void printname(){
System.out.println(saysomething);
}
}
class TestingAbstractInterfaceApp{
public static void main(String[] args){
AbstractInterface[] abstract_list = {new Test4("Helen") , new Test3("Hey , say my name")};
for(AbstractInterface item : abstract_list){
item.printname();
}
}
}
Question:
I am sensing there is something wrong with what I am doing in my code. But I cannot quite explain how come the code still works when theoretically, it is impossible to instantiate an abstract class and interface. Am I actually instantiating an abstract class and an interface in the examples shown above ? Because this seems like exactly what I have done, as I have a new type for the abstract class and interface. Please correct me, if my logic is wrong or if I am using the wrong words.
Update:
SO I guess my misunderstanding is about type. I always thought type can only refer to normal Java classes but not abstract classes and interfaces. How does "type" actually work? Is it creating a reference?
Why do you think you are actually instantiating AbstractClass and AbstractInterface?
new Test1("JEFFFFFF") , new Test2("Hey , say something"), new Test4("Helen") , new Test3("Hey , say my name") are all instantiating concrete classes, not abstract ones.
If you refer to AbstractClass[] abstractclass_list = as proof of instantiating abstract classes, that is wrong. Here, you declare an array whose elements are of type AbstractClass, and Test1 and Test2 are (since they extend AbstractClass).
UPDATE
You could have something like this AbstractClass abs = new Test1("hey"); and what it does is it creates a new instance of class Test1, and references that instance from variable abs. abs's concrete type is Test1, but only methods declared in AbstractClass are visible on it. If you want to call methods of Test1, you would have to cast it first.
AbstractClass abs = new Test1("hey");
abs.printname(); // this is ok, and it calls `printname() implemented in Test1
abs.someTest1Method(); // this is NOT ok, someTest1Method() is not visible to abs
((Test1)abs).someTest1Method(); // this is ok, abs is cast to Test1, but would fail if abs was instantiated as 'abs = new Test2("t2")' (would throw ClassCastException)
You are not instantiating your abstract class or your interface. You are instantiating concrete classes that extend your abstract class (Test1 and Test2) or implement your interface (Test3 and Test4).
It's allowed to assign an instance of a concrete class to a variable whose type is an interface or an abstract class. In fact, it's even encouraged.
You aren't instantiating either an abstract class, nor an interface. You are just using the inherent upcasting ability from subclasses to superclasses.
Ignoring the array, and using just the first object, this would be equivalent to the implicit upcasts:
AbstractClass myObject = new Test1("JEFFFFFF");
and
AbstractInterface myObject = new Test1("JEFFFFFF");
So, in the code:
AbstractClass[] abstractclass_list = {
new Test1("JEFFFFFF") ,
new Test2("Hey , say something")};
You are instantiating objects of the concrete classes Test1 and Test2 - the Array contains references to the underlying (and common) abstract base class.
Similarly, in the second example, you are obtaining an array of interface references.
In short I would like to say that,
Parent(here, Abstract/Iterface) can refer, it's child(here, concrete class).
So here, reference variable can refer it's child class's instance.
Just note this concept in your brain, it will fix all your problem regarding, Dynamic Dispatcher, Inheritance related....!!!
You are not instantiating an abstract class and an interface,
you are instantiating some specific implementations of that abstract class and of that interface.
If you declare a list of AbstractClass or AbstractInterface you can just calls methods declared on your superclass or interface but not these declared on your specific implementations (Test1, Test2, Test3 and Test4).
Is there a use case where we would need an abstract class with no methods defined in it? I bumped into creating such an abstract class just for the sake of generics so that users will pass only subtypes of this class. But I want to know if either is valid or there is a better way to do it.
Having an abstract class with no methods is legal, yet entirely pointless. You use abstract classes to share implementation. If a class has no methods, it has no implementation to share.
If you need to share some common variables (I assume that your abstract class has at least some fields, otherwise it is entirely empty) you would be better off with composition and an interface, like this:
class CommonData {
// Some getters and setters for items that you wish to share
}
interface WithCommonData {
CommonData getCommonData();
}
Your classes can put the common data as a member, and implement the interface WithCommonData, giving you access to the common data, and letting the classes keep their inheritance structure.
If you need to "mark" a user class, doing it with a "marker interface" (i.e. an interface with no methods) is a lot more flexible, because the users retain an ability to build their own chain of inheritance.
Creating an abstract class just because other classes should be of that type is not neccessary. This can instead be achieved using interfaces.
Since a class only can extend one class but implement any number of interfaces, using an interface as an instance validator will not limit a solution with respect to inheritance.
Example:
public interface Vehicle {
// No methods, we just want several classes to be identified as of type Vehicle
}
public class Car implements Vehicle {
// is a vehicle
}
public class Motorcycle implements Vehicle {
// is a vehicle
}
public class Banana {
// is not a vehicle
}
public class Main {
public static void main(String[] args) {
Object o = new Car();
if(o instanceof Vehicle) {
// Ok
}
Object p = new Banana();
if(p instanceof Vehicle) {
// Will never get here
}
}
}
I have two classes that extends a third class, i.e.
public class class_a extends parent_class
and
public class class_b extends parent_class
My question is it possible to have a third class to create a reference to a class based on condition? i.e.
public void test() {
parent_class b;
if (cond)
b = new class_a();
else
b = new class_b();
}
Is there a way to do that?
I don't want to create variables per type of class, I will only use one throughout the life time of this function.
That is exactly what the factory design pattern is for.
http://en.wikipedia.org/wiki/Factory_method_pattern
This might also be of use Factory Pattern. When to use factory methods?
Yes.
Polymorphism allows you threat subclass as base class.
So, you can write method with parent_class return value type, like so:
parent_class create(boolean condition)
{
return condition ? new class_a() : new class_b();
}
As #John answered, it is called Factory method.
P.S. In Java, you better should name classes using CamelCase, like ClassA and ParentClass. Code style.
i have an abstract class BaseClass with a public insert() method:
public abstract class BaseClass {
public void insert(Object object) {
// Do something
}
}
which is extended by many other classes. For some of those classes, however, the insert() method must have additional parameters, so that they instead of overriding it I overload the method of the base class with the parameters required, for example:
public class SampleClass extends BaseClass {
public void insert(Object object, Long param){
// Do Something
}
}
Now, if i instantiate the SampleClass class, i have two insert() methods:
SampleClass sampleClass = new SampleClass();
sampleClass.insert(Object object);
sampleClass.insert(Object object, Long param);
what i'd like to do is to hide the insert() method defined in the base class, so that just the overload would be visible:
SampleClass sampleClass = new SampleClass();
sampleClass.insert(Object object, Long param);
Could this be done in OOP?
There is no way of hiding the method. You can do this:
#Override
public void insert(Object ob) {
throw new UnsupportedOperationException("not supported");
}
but that's it.
The base class creates a contract. All subclasses are bound by that contract. Think about it this way:
BaseObject b = new SomeObjectWithoutInsert();
b.insert(...);
How is that code meant to know that it doesn't have an insert(Object) method? It can't.
Your problem sounds like a design problem. Either the classes in question shouldn't be inheriting from the base class in question or that base class shouldn't have that method. Perhaps you can take insert() out of that class, move it to a subclass and have classes that need insert(Object) extend it and those that need insert(Object, Object) extend a different subclass of the base object.
I don't believe there's a clean way to completely hide an inherited method in Java.
In cases like this, if you absolutely can't support that method, I would probably mark that method as #Obsolete in the child class, and have it throw a NotImplementedException (or whatever the equivalent exception is in Java), to discourage people from using it.
In the end, if you inherit a method that does not make sense for your child class, it could be that you really shouldn't inherit from that base class at all. It could also be that the base class is poorly designed or encompasses too much behavior, but it might be worth considering your class hierarchy. Another route to look at might be composition, where your class has a private instance of what used to be the base class, and you can choose which methods to expose by wrapping them in your own methods. (Edit: if the base class is abstract, composition might not be an option...)
As Cletus points out, this is really a design problem, in that you are trying to create a child class that does not obey the contract of its parent class.
There are rare circumstances where working around this by e.g. throwing an exception might be desirable (or at least an acceptable compromise -- for example, the Java Collections Framework) but in general it's a sign of poor design.
You may wish to read up on the Liskov substitution principle: the idea that (as Wikipedia puts it) "if S is a subtype of T, then objects of type T in a program may be replaced with objects of type S without altering any of the desirable properties of that program". By overriding a method to throw an exception, or hiding it any other way, you're violating this principle.
If the contract of the base class' method was "inserts the current object, or throws an exception" (see e.g. the JavaDoc for Collection.add()) then you could argue you're not violating LSP, but if that is unexpected by most callers you may want to rethink your design on these grounds.
This sounds like a badly designed hierarchy -
If no default exists and the user shouldn't call the method at all you can mark the method as #Deprecated and throw an UnsupportedOperationException as other posters have noted. However - this is really only a runtime check. #Deprecated only throws a compiler warning and most IDEs mark it in some way, but there's no compile time prevention of this. It also really sucks because it's possible to get the child class as a parent class reference and call the method on it with no warning that it's "bad" at all. In the example below, there won't be any indication until runtime that anything's wrong.
Example:
// Abstract base builder class
public abstract class BaseClassBuilder {
public final doBuild() {
BaseClass base = getBase();
for (Object obj : getObjects() {
base.insert(obj);
}
}
protected abstract BaseClass getBase();
protected abstract Object[] getObjects();
}
// implementation using SampleClass
public class SampleClassBuilder extends BaseClassBuilder {
#Override
protected BaseClass getBase() {
return new SampleClass();
}
#Override
protected Object[] getObjects() {
Object[] obj = new Object[12];
// ...
return obj;
}
}
However, if a sensible default exists, you could mark the inherited method as final and provide the default value inside of it. This handles both the bad hierarchy, and it prevents the "unforseen circumstances" of the above example.
Example:
public abstract class BaseClass {
public void insert(Object object) {
// ...
}
}
public class SampleClass extends BaseClass {
public static final Long DEFAULT_PARAM = 0L;
public final void insert(Object object) {
this.insert(object, DEFAULT_PARAM);
}
public void insert(Object object, Long param) {
// ...
}
}