I would like to store the class object of several classes that extend an abstract class in an array list. Please be aware, that I have to use an abstract class and no interface, because the class Country will contain more functionality.
The idea is to later access this class objects, create an object of them and call a method.
Question: How can I achieve this, because the following code produces errors.
import java.util.ArrayList;
public class Main
{
public static void main(String args[]) {
new Main();
}
public Main() {
// The idea is to add the class of all specific countries to the countries array
ArrayList<Class<Country>> countryclasses = new ArrayList<Class<Country>>();
// Doesn't work
countryclasses.add(England.class);
// Doesn't work
Class<Country> englandclass = England.class; // Error
countryclasses.add(englandclass);
// Doesn't work
England england = new England();
Class<Country> country = england.getClass().getSuperclass().getClass();
// Class<Country> country = england.getClass().getSuperclass().getClass();
countryclasses.add(country);
for(Class<Country> countryclass : countryclasses) {
// Create an object from the class
// Call the getName() method
}
}
public abstract class Country {
abstract String getName();
}
public class England extends Country {
public String getName() {
return "England";
}
}
}
If you really want to have a List<Class> instead of using a polymorphic collection of instances, you can use an upper-bounded wildcard to define classes that will be Country or extend it:
List<Class<? extends Country>> countryclasses = new ArrayList<Class<? extends Country>>();
Class<? extends Country> englandclass = England.class;
countryclasses.add(englandclass);
Related
I have a following Java Code where enum data type is used to create instances of the base class as following:
Main Abstract Class:
public abstract class Element{
static enum elements{
quad8{Element create(){return new ElementQuad2D();}};
abstract Element create();
}
public static Element newElement (String name){
el=elements.valueOf(name);
return el.create();
}
public Element (String name, int nind, int nstress){
this.name = name;
/*Do Something Else*/
}
}
SubClass:
class ElementQuad2D extends Element{
public ElementQuad2D(){
super("quad8",8,4);
}
}
How to create enum type as above such that I can create the instance of different subclass based on element name like "quad8" in PYTHON?
This can be easily achieved with a dictionary from a string to the class. The use of subclasses doesn't play a role here:
class Element: pass
class ElementQuad2D(Element): pass
mapping = {'quad8': ElementQuad2D}
obj = mapping['quad8']()
print(obj)
# <__main__.ElementQuad2D object at 0x01D70BD0>
i need to declare a list which should accept only the parent class objects and it should not allow the sub class objects.
parent class:
public class ParentClass {
private String parentAttr;
public String getParentAttr() {
return parentAttr;
}
public void setParentAttr(String parentAttr) {
this.parentAttr = parentAttr;
}
}
Sub class:
public class SubClass1 extends ParentClass {
private String attr1;
public String getAttr1() {
return attr1;
}
public void setAttr1(String attr1) {
this.attr1 = attr1;
}
}
Main class:
public class MainClass {
public static void main(String[] args) {
ParentClass parentClass=new ParentClass();
SubClass1 subClass1 = new SubClass1();
List<ParentClass> list=new ArrayList<ParentClass>(); // modify this declaration such that it should accept only the parent class objs
list.add(parentClass);
list.add(subClass1); // this should not happen. only parent class objects should be added in the list
}
}
I tried using generics as well. but it is not working. is there any way to achieve this in java generics?
You can Implement the List interface and provide your own implementation for the List.add(int index, E element) method and check if the element is instanceof the parent Class and not an instanceof the child Class in your implementation.
You can also extend the ArrayList Class and Override all the methods that add elements to the ArrayList and check if the element is instanceof the parent Class and not an instanceof the child Class in your implementation and call the Super method for process of adding the element(s).
No. You just can't stop it. We can use every Child as a Parent. Every Child extends Parent and apparently it's a Parent as well.
Could someone explain in the following example why the interface method can be called directly when it is passed as a parameter in a class constructor? I try to search a rule in the Java language specification but can not find one.
public interface Interface {
public void foo();
}
public class Main {
public Main() {}
public Main(Interface obj) {obj.foo();}
public static int test() {return 123;}
}
Is just a polymorphic behaviour, Java expects an implementation of the method of that interface.
That means, any class which implements that method is an Interface, so you can have many many different implementations of that method.
Let's say:
public class ImplementedInterface implements Interface
{
public void foo()
{
System.out.println("Hey!, i'm implemented!!");
}
}
So when you call:
Interface aux = new ImplementedInterface();
Main m = new Main(aux);
The text "Hey!, i'm implemented!!" will be printed.
You can call foo method from Interface reference because it can hold only object of class that implements Interface, so it will provide body for foo method.
Now thanks to late binding Java will use code of object class when needed.
I think that you are confused, you think cuase it's Interface type it's an interface
public Main(Interface obj) {
obj.foo();
}
obj is an object from a concrete implementation of Interface.
You may want to see some common design pattern that take this approach such as Strategy Pattern
For example :
public interface Searcher {
void search(String text, List<String> words);
}
public class BinarySearcher implements Searcher{
#Override
public void search(String text , List<String> words){
//code here
}
}
public class LinearSearcher implements Searcher{
#Override
public void search(String text ,List<String> words ){
// code here
}
}
public class WordContext {
private Searcher searcher;
private List<String> words;
public void makeSearch(String text){
searcher.search(); // you only know at runtime what subtype will be searcher
}
// here you inject by contract
public void setSearcher(Searcher searcher){
this.searcher= searcher;
}
// here you inject by contract
public void setWords(List<String> words){
this.words = words;
}
}
That's the main advantage you guide by abstract contract instead of concrete implementation.
In this example you can change the searcher injecting it, can be a linearSearcher or a binarySearcher, that's the polymorphic magic!
Here is where Programming to an interface, not an implementation comes into play. Your method is expecting an object of the class that that implements the interface
I would explain it with an example.
Let us say I have
LinkedList<String> ll = new LinkedList<String>();
and I have
ArrayList<String> al = new ArrayList<String>();
Now I have a method -
public void deleteFirst(List aList) {
System.out.println(aList.remove(0));
}
Now you can pass both ll and al to the deleteFirst method. Which means your method is passed an object of the class that that implements the interface.
In the example ArrayList and LinkedList both implement the List interface and therefore can be passed to the method. Ultimately what your method is getting is an object of the class that implements the List interface.
If I have an Enum as a helper in a Java class, is there any way to refer to that Enum outside of the class it's helping?
Basically, what I have is this:
class Account extends MyClass {
HashMap<Property, String> property = new HashMap<Property, String>();
public Account() {
}
public enum Property {
USERID,
PASSWORD;
}
}
I want to be able to access the Property enum outside of the Account class.
The reason I want to do this is because this is a subclass of a another, and I want to be able to access the properties of a given subclass without refering to a unique enum name (ie: without refering to each one as, say, AccountProperty or ResearchProperty or TaskProperty... etc).
Your enum is public so you just can use Account.Property to access it from outside the Account class
EDIT :
If I got what you need, you'd like to do something like
Property p = Account.Property.PASSWORD;
Property p1 = Product.Property.CODE;
where Product is
public class Product extends MyClass{
HashMap<Account.Property, String> property = new HashMap<>();
public Product() {
}
public static enum Property {
CODE,
PRICE;
}
}
and you want to do this in your MyClass.
The problem is that both the two lines require an import and you can't import two classes with the same name, so the only solution is to do something like this
Account.Property p = Account.Property.PASSWORD;
Product.Property p1 = Product.Property.CODE;
I guess that you've got to deal with the instanceof to use the right Property enum for each class, as there's no way to extend an enum!
maybe something like the following (but this has no type checking):
import java.util.*;
abstract class MyClass {
Map<Object,String> properties=new HashMap<Object,String>();
}
class Account extends MyClass {
enum Property {
userid,password
}
//static Set<Property> keys=EnumSet.allOf(Property.class);
}
class Research extends MyClass {
enum Property {
red,green;
}
static Set<Property> keys=EnumSet.allOf(Property.class);
}
public class So10666881 {
public static void main(String[] args) {
Account account=new Account();
account.properties.put(Account.Property.userid,"user");
account.properties.put(Account.Property.password,"pass");
for(Account.Property property:Account.Property.values())
System.out.println(property+"="+account.properties.get(property));
}
}
Just declare the enum as a public top level enum class (in its own file)
I am trying to create a generic Identifier class which I would be able to use as follows:
public class TestGenericIdentifier {
public static void main(String[] args) {
Identifier<Car> carId = new Identifier<>(Car.IdentifierType.LICENSE_PLATE, "123 XYZ");
Identifier<Person> personId = new Identifier<>(Person.IdentifierType.SOCIAL_SECURITY, "123456");
System.out.println(carId);
System.out.println(personId);
}
}
To get there, I started by creating an Identifiable interface:
public interface Identifiable<T extends Enum> {}
The idea being that a class that implements Identifiable needs to provide an enum T in its declaration which is the type of the first parameter of the Identifier constructor:
public class Identifier<E extends Identifiable<T>> { //does not compile
public Identifier(T type, String value) {
//some code
}
}
Now the code above does not compile as I can only use Identifiable (no parameter T) on the first line. If it worked I would be able to write the following two classes:
public class Car implements Identifiable<Car.IdentifierType>{
public enum IdentifierType {
SERIAL_NUMBER,
LICENSE_PLATE;
}
}
public class Person implements Identifiable<Person.IdentifierType> {
public enum IdentifierType {
DATABASE_ID,
SOCIAL_SECURITY;
}
}
Is there a way to do that using generics?
EDIT
One way is to compromise conciseness and keep compile-time type checking by doing:
public class Identifier<T extends Enum> {
public Identifier(T type, String value) {
}
}
and the main function becomes:
Identifier<Car.IdentifierType> carId = new Identifier<>(Car.IdentifierType.LICENSE_PLATE, "123 XYZ");
Identifier<Person.IdentifierType> personId = new Identifier<>(Person.IdentifierType.SOCIAL_SECURITY, "123456");
public class Identifier<E extends Identifiable<? extends Enum>> {
public Identifier(Enum type, String value) {
//some code
}
}
Might be enough for what you want
You can get this to compile by tweaking your code a bit but I'm not sure it's what you want. The following seems to work for me.
Identifier<Car.IdentifierType, Car> carId =
new Identifier<Car.IdentifierType, Car>(Car.IdentifierType.LICENSE_PLATE,
"123 XYZ");
public static class Identifier<T extends Enum, E extends Identifiable<T>> {
public Identifier(T type, String value) {
// some code
}
}
The question is why do you want to do this? If you edit your question some more with the background, I can edit my answer to be more helpful.