This question already has answers here:
Upcasting/Downcasting in Java
(3 answers)
Closed 3 years ago.
I am trying to solve the following problem
I have made the following hierarchy.
public abstract class Employee{
private String name;
private Integer id;
protected Type type;
Employee(){}
Employee(String name,Integer id){
this.name = name;
this.type = type;
}
abstract public void calculatePay();
protected void benifits(){
System.out.println("Basic Benifts");
}
public void printType(){
System.out.println(this.type);
}
}
public class Intern extends Employee{
Intern(){
super("default",123);
}
Intern(String name,Integer id){
super(name,id);
this.type = Type.Intern;
}
public void calculatePay(){
System.out.println("Intern Pay");
}
}
class Developer extends Employee{
Developer(){
super("default",123);
}
Developer(String name,Integer id){
super(name,id);
this.type = Type.Developer;
}
public void calculatePay(){
System.out.println("Developer Pay");
}
protected void benifits(){
super.benifits();
System.out.println("Developer Benifits");
}
}
class Manager extends Developer{
public Manager(){
super("default",123);
}
public Manager(String name,Integer id){
super(name,id);
this.type = Type.Manager;
}
public void calculatePay(){
System.out.println("Manager Pay");
}
public void benifits(){
super.benifits();
System.out.println("Manger Benifits");
}
public void foo(){
System.out.println("foo");
}
}
And the driver is as follows
class Driver{
public static void main(String args[]){
Employee manager = new Manager("Ali",1);
manager.calculatePay();
manager.benifits();
manager.printType();
manager.foo();
}
}
Type is an Enumeration.
Now the problem is that I can't access foo() method using dynamic approach. But when I do static polymorphism like Manager manager = new Manager() I can access it.
What is the particular reason of this behavior. Is my design correct? What would be a better design? And which design pattern should I use?
There is no need to have the Type enum, the class itself (i.e. Intern) represents the employee type.
Related to the issue of not being able to call manager.foo() is because from a variable of a specific type you can call only those methods which are declared on that type (class).
In your case, when you declare Employee manager = new Manager("Ali", 1); you can call methods which are declared on Employee, in this case foo() is declared on Manager class
When you do Employee manager = new Manager("Ali",1); even though you are creating a Manager instance but the type is Employee, since the type is Employee the compiler do not know manager.foo(); is.
So you have to defile a void foo() method it can be abstract also.
Related
I want to program a factory that creates two types of People which are "Employee" and "Entrepreneur". They both share the same basic "Person" attributes but they also implements their unique ones.
The problem is that if i want to return a method or an attribute that is not declared in the "Person" abstract class the program doesn't find it (since obviously I'm generating an object that is type "Person" and not specifically "Employee" or "Entrepreneur" ).
How do i tackle this problem?
This is the Demo class
public class Demo{
public static void main(String[] args){
PersonFactory pf = new PersonFactory();
Person p1 = pf.getPerson("Employee");
p1.presentation();
System.out.println(p1.getComplanyName());
}
}
This is the abstract class
public abstract class Person{
String name;
String surname;
abstract void presentation();
}
Those are the two concrete classes that extend Person
public class Entre extends Person{
int licenseNumber;
#Override
public void presentation(){
System.out.println("hi i'm an Entrepreneur");
}
public int licenseNumber(){
return licenseNumber;
}
}
public class Empl extends Person{
String companyName;
#Override
public void presentation(){
System.out.println("hi i'm an employee");
}
public String getCompanyName(){
return companyName;
}
}
Finally the Factory
public class PersonFactory{
public Person getPerson(String type){
if(type.equalsIgnoreCase("ENTREPRENEUR")){
return new Entre();
}
else if(type.equalsIgnoreCase("Employee")){
return new Empl();
}
return null;
}
}
This is my first class:
package trickycorejava;
public class InnerClass {
int id;
oneClass oneClass;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public trickycorejava.oneClass getOneClass() {
return oneClass;
}
public void setOneClass(trickycorejava.oneClass oneClass) {
this.oneClass = oneClass;
}
public InnerClass(int id, trickycorejava.oneClass oneClass) {
this.id = id;
this.oneClass = oneClass;
}
public InnerClass(int id){
this.id = id;
}
}
class oneClass {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
This is the class where the main method exists, observe that the package is different:
package trickycorejava.constructor;
import trickycorejava.InnerClass;
public class InnerClassTest {
public static void main(String[] args) {
InnerClass innerClass = new InnerClass(1);
}
}
How can I initialize the InnerClass with constructor in this case? If I use
InnerClass innerClass = new InnerClass(1, new oneClass("Test"));
I get the error that oneClass is not public cannot be access from outside package.
As Turing85 pointed out the oneClass should be in it's own file, otherwise it's going to be package-private which means you can only access it from classes of the same package.
Is there another way? There is, but it's not going to be a simple constructor call. Using reflection you can bypass class, field and method invocation protection.
public class InnerClassTest {
public static void main(String[] args) throws Exception {
Constructor<OneClass> constructor = OneClass.class.getDeclaredConstructor(String.class);
constructor.setAccessible(true);
OneClass instance = constructor.newInstance("John");
InnerClass innerClass = new InnerClass(1, instance);
}
}
What this does is that it finds the constructor that is private to Main because the class is package-private. Then it disables the protection of it, note that these are temporary, the Constructor object is a new reference and only allows the invocation via this reference.
But I don't recommend doing this extensively. Reflection has some use cases, mainly to aid programmers in frameworks like Spring, but otherwise it can break object oriented patterns.
Today I had test in OOP and I was given the following task to code:
Imagine you have two classes: Employee (which represents being an employee) and Ninja (which represents being a Ninja). An Employee has both state and behaviour; a Ninja has only behavior. You need to represent an employee who is also a ninja (a common problem in the real world). By creating only one interface and only one class (NinjaEmployee), show how you can do this without having to copy method implementation code from either of the original classes. Test your code in main method
I did not really understand the problem well, but this is the solution I came with (I know it's not what was asked):
I created 4 classes except main. As Employee has state and behaviour I came up with this code:
public class Employee {
private int ID;
private String Name;
private double salary;
public Employee(int ID, String Name, double salary) {
this.ID = ID;
this.Name = Name;
this.salary = salary;
}
public int getID() {
return ID;
}
public void setID(int ID) {
this.ID = ID;
}
public String getName() {
return Name;
}
public void setName(String Name) {
this.Name = Name;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
public void startWorking() {
System.out.println("Started Working");
}
}
Class ninja has only behaviour:
public class Ninja {
public Ninja(){}
public void moveNinja(){
System.out.println("Ninja moved");
}
}
Class NinjaEmployee:
public class NinjaEmployee extends Employee implements MyInterface {
public NinjaEmployee(int ID, String Name, double salary) {
super(ID, Name, salary);
}
public void moveNinja() {
System.out.println("Ninja Moved");
}
}
Interface which does not make sense in my code:
public interface MyInterface {
public void moveNinja();
public void startWorking();
}
Main class:
public static void main(String[] args){
MyInterface em = new NinjaEmployee(123,"Sandro",1000000);
em.moveNinja();
em.startWorking();
}
My question is following:
1) Specifically/Technically what was asked in test?
2) What would be correct approach/code for given problem?
Nice question.
The key point of the question is:
we should use one interface.
Ninja class should have some methods (not attributes).
So we should try to use these key point.
I provide a class diagram below:
First of all: We have Employee class and implement it like other simple classes. It has some implemented attributes and classes.
Secondly: We have an Interface named Ninja_Interface that have some method declarations about ninja. (moveNinja1 and moveNinja2)
Thirdly: Ninja Class that implemented (or Realized) Nijna_Interface and have some implementation of any method declarations in Ninja_Interface.
Fourthly: the NinjaEmployee class. It inherited from Employee. So it has all Employee's attributes and methods. Also it implements Ninja_Interface. So it should implements all Ninja_Interface methods declarations. On the other hand, NinjaEmployee have an instance of Ninja (notice that Ninja class implements all Ninja_Interface methods). So, In Ninja_Employee class, in implementation of Ninja_Interface methods, we can use Ninja instance methods to call.
For example some parts of NinjaEmployee is like below code:
private Ninja ninja=new Ninja();
public void moveNinja1()
{
ninja.moveNinja1();
}
public void moveNinja2()
{
ninja.moveNinja2();
}
Main question is: why Ninja class should have only some methods?
It is because of Ninja class is just the implementations of Ninja_Interface methods and there no need to have attributes. So instances of Ninja class are the same. So we can declare Ninja attribute in NinjaEmployee as static attribute.
Finally: we can add some attributes of ninja into NinjaEmployee class too.
I don't know correct answer (task is kinda not very strictly defined, there is some unclear moments), but i would do something like this:
public interface IAmNinja {
public void moveNinja();
}
public interface IAmEmployer {
public void startWorking();
}
public class NinjaEmployee implements IAmNinja, IAmEmployer {
private Ninja _ninja;
private Employer _employer;
public NinjaEmployee(int ID, String Name, double salary) {
_employer = new Employer(ID, Name, salary);
_ninja = new Ninja();
}
public void moveNinja() {
_ninja.moveNinja();
}
public void startWorking() {
_employer.startWorking();
}
}
You cant create 1 object of 2 class es
You can extend class so whenever child class is instantiated it calls parent class constructor
Then You can create object of another class in that constructor
Add employees in array and add option to add employee in ninja? 1.yes or 2.no?
if yes , add to ninja..then in main method print names of ninja using for loop one by one
This question already has answers here:
Returning an objects subclass with generics
(4 answers)
Closed 5 years ago.
If this question has already been asked i could not find it.
Here is a simplified example of what i am trying to do.
public static class SuperClass {
private String name;
public <? extends SuperClass> setName(String name)
this.name = name;
return this;
}
}
public static class SubClass extends SuperClass {
private int id;
public void setId(int id) {
this.id = id;
}
}
//Usage
SubClass subclass = new SubClass();
subClass.setName("Some Name").setId(0);
So what i need is for setName to return whatever class its actually called from as oppose to the class its defined in. (In this case it would return an instance of SubClass instead of SuperClass, but if for example SubClass was then extended by SubClass2 it would return an instance of SubClass2)
Is what im asking possible via generics?
You can add a type to the SuperClass declaration and use it in the returned type of the setName() method.
It will force all inherited subclass to return the type declared in their extending declaration to SuperClass.
But to achieve it you should cast this to T in setName().
public class SuperClass<T extends SuperClass<T>> {
private String name;
public T setName(String name) {
this.name = name;
return (T) this;
}
}
And declare subclass in this way :
public class SubClass extends SuperClass<SubClass> {
...
public void setId(int i) {
...
}
...
}
And now you could do :
SubClass subclass = new SubClass();
subclass.setName("Some Name").setId(0);
Another way to address the problem :
Using covariant return types in the overrided methods will allow you to specify subclass in the returned type. You can use it instead of generics.
The single thing to notice : you will have to be careful to define explicitly the return type by overriding the method in each subclass.
Without generics, nothing will force you to do it (but an unit test).
public class SuperClass {
private String name;
public SuperClass setName(String name) {
this.name = name;
return this;
}
}
public class SubClass extends SuperClass {
#Override
public SubClass setName(String name) {
super.setName(name);
return this;
}
public void setId(int i) {
...
}
}
I need help fixing my code with the basic concepts listed above. To save from clutter, I took a screen shot of the directions here: https://imgur.com/SdiotUi
However, when I run my code it isn't working. I know there are a lot of errors but I'm having trouble fixing them even though I've spent the past few hours googling the correct way to do this.
When I create the first constructors I am not sure if I am assigning the name and legs correctly, I am having trouble returning "true", I get an error calling the parent class taking one argument, and I don't think I am overriding the abstract class correctly.
My code:
public class Animal1 {
private String animalName;
public int numberOfLegs;
public Animal1(String name){
name = animalName;
name = "John";
}
public Animal1(String name, int legs){
name = animalName;
legs = numberOfLegs;
name = "Jack";
legs = 4;
}
public String getName(){
return animalName;
}
public int getLegs(){
return numberOfLegs;
}
public void isAMammal(){
return true;
}
public void isCarnivorous(){
return true;
}
public abstract class getHello{
}
}
public class Cat1 extends Animal1{
public Cat1(String name){
Animal1.name;
}
public abstract class getHello{
return "Meow";
}
}
public class Dog1 extends Animal1{
public Dog1(String name){
Animal1.name;
}
public abstract class getHello{
return "Woof";
}
}
public abstract class Animal1 { // If you want to have an abstract method, declare the class as abstract
private final String animalName;
private final int numberOfLegs; // better of using private and make it final since it's not going to change.
public Animal1(final String name, final int legs){ //better making the input parameters final since they are not supposed to be changed
//name = animalName;
//legs = numberOfLegs;//it assigned the field to an input parameter. that will take no effect on the object created.
animalName = name;
numberOfLegs = legs;
}
public String getName(){
return animalName;
}
public int getLegs(){
return numberOfLegs;
}
public boolean isAnimal(){ //boolean function needs a return type too!!
return true;
}
public boolean isCarnivorous(){
return true;
}
public abstract String getHello(); // an abstract method has same requirement as a normal method besides the abstract modifier. it will need a return type. And it ends with a semicolon
}
public class Cat1 extends Animal1{
public Cat1(final String name){
super(name, 4); //use super to call parent constructor
}
#Override
public String getHello(){
return "Meow";
}
}
public class Dog1 extends Animal1{
public Dog1(final String name){
super(name, 4);
}
#Override
public String getHello(){
return "Woof";
}
}
First, it looks like a few of your methods are declared as classes. I assume you wanted to make them abstract methods. They need to be changed to:
public abstract String getHello();
Note that abstract methods can only be declared in an abstract class. So, you need to redefine Animal1 as abstract.
public abstract class Animal1
Next, when you implement the abstract method, you define it as
public String getHello()
If you are using an IDE like Eclipse it will automatically offer to generate this method.
Finally, when using your constructor in your child classes like Cat1, you are trying to set "name" as if it was a static variable and bypassing the constructor you already had set for Animal1. The best way to correct this is to change the constructor in Cat1 and Dog1 to call the super constructor.
public Cat1(String name){
super(name);
}