Is there a way to cast an Object to its "lowest" class? In my case, "Arc" and "Line" extend "Curve". I want to save both in an ArrayList and then do something with them, depending on what class it is. This example outputs "curve", "curve" but I want it to be "arc", "line". Thanks for your help!
public class Test4 {
public static void main(String[] args) {
ArrayList<Curve> curves = new ArrayList<>();
Arc arc = new Arc(new Point(0, 0, 0), 0, 0, 0);
Line line = new Line(new Point(0, 0, 0), new Point(1, 0, 0));
curves.add(arc);
curves.add(line);
for (Curve i : curves) {
test(i);
}
}
public static void test(Line l) {
System.out.println("line");
}
public static void test(Arc a) {
System.out.println("arc");
}
public static void test(Curve c) {
System.out.println("curve");
}
}
EDIT: Thank you for your answers! It works so far, but my problem is a little more complicated. What I want to do is find the intersection Point(s) of two geometrical Objects (so Line - Arc, Line - Line, Line - Circle etc.)
public class Line{
//constructor and other methods
public Point[] intersection(Circle circle) {
//some code
}
public Point[] intersection(Line line) {
//some code
}
public Point[] intersection(LineSeg s) {
//some code
}
}
I want to access these methods with Curve objects, so in abstract class Curve there is a method intersection (Curve). When I call this method it returns an empty Array, because it called the method from Curve class. How can I tell Java to use the methods from classes Arc, Line etc and not from Curve?
public abstract class Curve {
public Point[] intersection(Curve c) {
return new Point[] {};
}
}
Method overloading is resolved during compilation, based on the static type of the parameters passed to the method, therefore, when you pass a variable of type Curve, the method static void test(Curve c) is always chosen, regardless of the runtime type of the objects referenced by the variable i.
You can replace your static test methods with instance methods, and thus use method overriding:
In Line class:
public void test() {
System.out.println("line");
}
In Arc class:
public void test() {
System.out.println("arc");
}
In Curve class:
public void test() {
System.out.println("curve");
}
And change your loop to
for (Curve i : curves) {
i.test();
}
That's the most common design error you are making there.
As #Eran said you shall move the logic from global handler into the class instances.
The problem can be specified in another way:
You cast object like Arc and Line to its more generic form - Curve
And then try to differentiate between Arc and Line objects.
For Arcs output message that the object is Arc
For Lines output message that the object is Line
To differentiate the object classes you must use Java mechanisms:
Execute its method (methods of objects are the best way to determine the type of object)
Use instenaceof operator
So the best, proffesional approach is to implement methods test in each of the classes:
public void test() {
System.out.println("Your type");
}
It's not advised to use instanceof because it generate bugs and you can write a code like this one:
public static void test(Curve c) {
if(c instanceof Arc) {
System.out.println("Arc");
return;
}
System.out.println("Something else");
}
In that case if you add new class like OtherGeometricalObject you may forget to change implementation of test to add line:
if(c instanceof OtherGeometricalObject) {
System.out.println("OtherGeometricalObject");
return;
}
That's why instanceof is in most cases a really bad deal and should be avoided!
If you would like to differentiate between objects like in the example
(do something for objects of one class and something other for other classes objects)
just use class method!
It's the mechnism designed for that purpose!
I hope my explanation is rich and helpful :)
You want to get a OOP behavior for each subclass where the behavior depends on the runtime class but overloading with a static modifier will not allow that.
The selection of the method being done at compile time according to the declared type of the argument.
As Eran suggested, let each subclass defines its test() method and invoke the method on an instance of it.
Besides, what you want can be performed with an Object method.
The method toString() is designed for returning a String representing of the object.
You can directly use it in this way :
for (Curve curve : curves) {
System.out.println(curve);
}
If the default toString() method doesn't suit for you, you may
override it in subclasses.
In Line class :
public String toString() {
return "line";
}
In Arc class:
public String toString() {
return "arc";
}
In Curve class:
public String toString() {
return "curve";
}
Related
I've got the following code example:
class p {
public void druckauftrag() {
// ...
drucke();
}
public void drucke() {
System.out.println("B/W-Printer");
}
}
class cp extends p {
public void drucke() {
System.out.println("Color-Printer");
}
}
Calling the following lines:
cp colorprinter = new cp();
cp.druckauftrag();
There is no problem understanding why "cp.druckauftrag();" results in console output "Color-Printer".
But when I call:
p drucker = (p)colorprinter;
drucker.druckauftrag();
I get the same output - why?
Does the typecast overwrite the object "drucker" 's method "drucke" with "drucke" from colorprinter?
Thanks in advance for every explanation.
colorprinter does not stop being an instance of cp when you use the cast operator on it, so its implementation of public void drucke() does not change
What you are expressing with your (p)colorprinter casting is the kind of contract (interface) you expect the object colorprinter to satisfy, which includes a public method with the signature public void drucke(), but not any specific implementation.
And, by the way, this casting is already performed implicitly when you declare drucker of the type p, so (p) is redundant in p drucker = (p)colorprinter;. p drucker = colorprinter; will suffice.
Here you can learn more about typecasting.
Keep in mind that it's best practice to extend from abstract classes or interfaces and only #Override (implement) abstract methods. A better design of your code would be:
abstract class BasePrinter {
public void druckauftrag() {
// ...
drucke();
}
public void drucke();
}
class p extends BasePrinter {
public void drucke() {
System.out.println("B/W-Printer");
}
}
class cp extends BasePrinter {
public void drucke() {
System.out.println("Color-Printer");
}
}
But of course constraints don't always allow for that kind of redesign. Passing the base requirements as parameters to the constructor (dependency injection) instead of extending a base class can also be a good alternative:
interface Druckable {
void drucke();
}
class Druckauftrager {
Druckable dk;
Druckauftrager(Drukable dk){
this.dk = dk;
}
public void druckauftrag() {
// ...
dk.drucke();
}
}
class p implements Druckable {
public void drucke() {
System.out.println("B/W-Printer");
}
}
class cp implements Druckable {
public void drucke() {
System.out.println("Color-Printer");
}
}
Now, if you want to express that a printer requires or can have multiple printing capabilities (like both color and b/w), you just write the class with as much extra Drukable properties and constructor parameters as you want, for example:
class BlackAndWhiteOrColorPrinter {
p blackAndWhitePrintService;
cp colorPrintService;
Druckable selectedPrintService;
BlackAndWhiteOrColorPrinter (p blackAndWhitePrintService, cp colorPrintService){
this.blackAndWhitePrintService = blackAndWhitePrintService;
this.colorPrintService = colorPrintService;
this.selectedPrintService = blackAndWhitePrintService;
}
public void druckauftrag() {
// ...
selectedPrintService.drucke();
}
}
This way, you can even write a class MultiPrinter with a MultiPrinter(List<Druckable> printServices) constructor and add any number of printing modes to its list of printing services: p, cp, and whatever other implementation of Druckable with its public void drucke() comes in the future. It is also extra practical if you want to introduce unit testing, so you can provide mockup objects that force the particular conditions you want to test, like druke() throwing a PaperJamException, for example.
For more information on how interfaces, overriding and inheritance work, see https://docs.oracle.com/javase/tutorial/java/IandI/usinginterface.html
BTW, acording to the latest revision of the official java code conventions guide and also by de facto standard, classes in Java should use CamelCase naming convention. You can also benefit greatly from using semanting naming on all your definitions, like BlackAndWhitePrinter blackAndWhitePrinter and ColorPrinter colorPrinter.
colorprinter is an instance of cp. Even when you upcast it to p, it's drucke() method will be still the one from cp.
The difference is that after you upcast colorprinter, you will not be able to invoke the methods that cp defines on its own.
When you create an object using new operator, memory is allocated in heap. Methods and fields are actually there depending upon the concrete actual class of the object.
Alter a sub class overrides and modifies a behavior from its super class, invoking the overridden method will always result in the modified behavior. Casting will only mean that the object of sub class is now represented by the super type as the object has a modified behavior for a method will always result in the modified behavior.
Suppose you have below classes
public class Fruit{
public void taste(){
System.out.println("depends upon the actual fruit");
}
}
public class Mango extends Fruit{
#Override
public void taste(){
System.out.println("sweet");
}
public void wayToExposeSuperMethod(){
super.taste();
}
}
In other words its like calling mango as a fruit but still mango remains mango.
For above code
Fruit fruit = new Mango();
fruit.taste(); // <-- this will output : sweet
((Mango)fruit).taste();// <-- this will output : sweet
fruit.wayToExposeSuperMethod(); // <-- this will not compile
((Mango)fruit).wayToExposeSuperMethod(); // <-- this will output : depends upon the actual fruit
It's a common practice to encapsulate code that often changes. In fact, it is often in the form of using an object to delegate the varying logic to. A sample would be the following:
public class SampleClass {
Object obj = new ObjectWithVaryingMethod();
public SampleClass(Object obj){
this.obj=obj;
}
public String getString(){
return obj.toString();
}
public static void main(String args[]){
SampleClass sampleClass=new SampleClass(new ObjectWithVaryingMethod());
System.out.println(sampleClass.getString());
}
}
class ObjectWithVaryingMethod{
#Override
public String toString(){
return "Hi";
}
}
Can you suggest what problems I may encounter when "encapsulation" is done on what doesn't vary? I find it to be a good coding conduct when the main class itself is the one that is often subject to change or improvement. A sample would be the following. In this second case, retrieving "Hi", which is the part that doesn't vary, was "encapsulated" in another class.
public class SampleVaryingClass {
public static void main(String args[]) {
//here I may opt to print getHi's value on sysout or on a dialog
System.out.println(ObjectWithNonVaryingMethod.getHi());
}
}
In a completely different class...
public class ObjectWithNonVaryingMethod {
private static final String hi = "Hi";
//"Hi" should always be returned
public static String getHi() {
return hi;
}
}
Can you give some pro's and con's on doing this?
Both code cannot be compared each other. One is static, another one isn't. I hope you understand the concept of encapsulating the object in the first code. Here is the pros and cons for the second one. Remember that static is "generally" bad, and do not support concurrency by default.
pros:
With getHi, you are keeping the string field private, meaning that it cannot be set from other source
Say that you need to do setHi from other source, you can add several guard clauses for it. This is called defensive programming.
public static setHi(String input){
if(input == null) { input = ""; } // can throw exception instead
hi = input;
}
cons:
It is static, needless to say
You don't get any advantage other than guard clauses. If your class is not static, you can swap it with other class implementing same interface, or other class inherited from that class.
The following example is a reduction of the real problem in that it tries to simplify is as much as possible.
I have a java interface, and several objects that implement that interface, like:
public interface Shape{
public void draw();
public void erase();
public boolean isDrawn();
}
public class Square implements Shape{
#Override
public void draw(){
//TODO: method implementation
}
#Override
public void erase(){
//TODO: method implementation
}
Override
public boolean isDrawn(){
//TODO: method implementation
return false;
}
}
public Triangle implements Shape{
//same as above
}
public Circle implements Shape{
//same as above
}
This is the structure of my program. By using AspectJ I want to have a map that holds each object that implements the interface. To do so I was trying to capture the constructors by using the following aspect:
public aspect ShapeHolderAspect{
private Map<Integer, Shape> map = new HashMap<>();
private int count = 0;
pointcut shapeInit(): call((Shape+).new(..));
Object around(): shapeInit() {
System.out.println("capturing new");
Shape shapeType = (Shape)proceed();
map.put(++count, shapeType);
return shapeType;
}
}
This code will work if I create a Shape using the following scenario:
public static void main(String[] args){
Shape myShape = new Circle();
}
However, I am using java language reflection, and so technically I don't call the "new" constructor. Instead I locate the path of the package, and create the object passing a string with the name of the class:
public static void main(String[] args){
String shapeClassName = args[0];
Class<?> classType = Class.forName("myPackage.figures" + "." + shapeClassName);
Shape myShape =(Shape)classType.getConstructor().newInstance();
}
By doing this way, AspectJ cannot detect that I am creating shapes. How do I fix this?
New, better version:
Well, while the old version below actually catches all constructor executions, an around advice on constructor execution returns null because the object in question has not been initialised yet. So you would end up with a map of null pointers in your aspect. In order to fix this you need to bind this() to a variable (sample code uses default package name):
public class Application {
public static void main(String[] args) throws Exception {
new Circle().draw();
((Shape) Class.forName("Triangle").getConstructor().newInstance()).isDrawn();
((Shape) Class.forName("Square").getConstructor().newInstance()).erase();
}
}
import java.util.HashMap;
import java.util.Map;
public aspect ShapeHolderAspect {
private Map<Integer, Shape> map = new HashMap<Integer, Shape>();
private int count = 0;
after(Shape shape): execution(Shape+.new(..)) && this(shape) {
System.out.println(thisJoinPointStaticPart);
map.put(++count, shape);
}
after() : execution(* Application.main(..)) {
System.out.println("\nList of shapes:");
for (int key : map.keySet())
System.out.println(" " + key + " -> " + map.get(key));
}
}
The output looks like this:
initialization(Circle())
initialization(Triangle())
initialization(Square())
List of shapes:
1 -> Circle#1a2961b
2 -> Triangle#12d03f9
3 -> Square#5ffb18
BTW, if you absolutely need an around advice because you want to do other things before and after object creation, it would look like this:
void around(Shape shape): execution(Shape+.new(..)) && this(shape) {
System.out.println(thisJoinPointStaticPart);
proceed(shape);
map.put(++count, shape);
}
Old, incomplete version:
Quite simply, just intercept constructor execution instead of call:
pointcut shapeInit(): execution(Shape+.new(..));
This way you weave into the called code (callee), not the calling code (caller). Consequently, it does not matter if the caller issues a reflective or normal call.
Found that the following pointcut will do the job:
pointcut lockReflectInit(): call(public Object java.lang.reflect.Constructor.newInstance(..));
This will however catch ALL calls of newInstance, and not just the ones that return Shape =(
Lets suppose I have the following two classes
public class alpha {
public alpha(){
//some logic
}
public void alphaMethod1(){
//some logic
}
}
public class beta extends alpha {
public beta(){
//some logic
}
public void alphaMethod1(){
//some logic
}
}
public class Test extends beta
{
public static void main(String[] args)
{
beta obj = new beta();
obj.alphaMethod1();// Here I want to call the method from class alpha.
}
}
If I initiate a new object of type beta, how can I execute the alphamethod1 logic found in class alpha rather than beta? Can I just use super().alphaMethod1() <- I wonder if this is possible.
Autotype in Eclipse IDE is giving me the option to select alphamethod1 either from class alpha or class beta.
You can do:
super.alphaMethod1();
Note, that super is a reference to the parent class, but super() is its constructor.
Simply use super.alphaMethod1();
See super keyword in java
You can't call alpha's alphaMethod1() by using beta's object But you have two solutions:
solution 1: call alpha's alphaMethod1() from beta's alphaMethod1()
class Beta extends Alpha
{
public void alphaMethod1()
{
super.alphaMethod1();
}
}
or from any other method of Beta like:
class Beta extends Alpha
{
public void foo()
{
super.alphaMethod1();
}
}
class Test extends Beta
{
public static void main(String[] args)
{
Beta beta = new Beta();
beta.foo();
}
}
solution 2: create alpha's object and call alpha's alphaMethod1()
class Test extends Beta
{
public static void main(String[] args)
{
Alpha alpha = new Alpha();
alpha.alphaMethod1();
}
}
It is possible to use super to call the method from mother class, but this would mean you probably have a design problem.
Maybe B.alphaMethod1() shouldn't override A's method and be called B.betaMethod1().
If it depends on the situation, you can put some code logic like :
public void alphaMethod1(){
if (something) {
super.alphaMethod1();
return;
}
// Rest of the code for other situations
}
Like this it will only call A's method when needed and will remain invisible for the class user.
Whenever you create child class object then that object has all the features of parent class.
Here Super() is the facilty for accession parent.
If you write super() at that time parents's default constructor is called.
same if you write super.
this keyword refers the current object same as super key word facilty for accessing parents.
Solution is at the end of this answer, but before you read it you should also read what is before it.
What you are trying to do would break security by allowing skipping possible validation mechanisms added in overridden methods.
For now lets imagine we can invoke version of method from superclass via syntax like
referenceVariable.super.methodName(arguments)
If we have classes like
class ItemBox{ //can sore all kind of Items
public void put(Item item){
//(1) code responsible for organizing items in box
}
//.. rest of code, like container for Items, etc.
}
class RedItemsBox extends ItemBox {//to store only RED items
#Override
public void put(Item item){ //store only RED items
if (item.getColor()==Color.RED){
//(2) code responsible for organizing items in box
}
}
}
As you see RedItemsBox should only store RED items.
Regardless which of the below we use
ItemBox box = new RedItemsBox();
RedItemsBox box = new RedItemsBox();
calling
box.put(new BlueItem());
will invoke put method from RedItemsBox (because of polymorphism). So it will correctly prevent BlueItem object from being placed in RedItemBox.
But what would happen if we could use syntax like box.super.put(new BlueItem())?
Here (assuming it would be legal) we would execute version of put method from ItemBox class.
BUT that version doesn't have step responsible for validating Item color. This means that we could put any Item into a RedItemBox.
Existence of such syntax would mean that validation steps added in subclasses could be ignored at any time, making them pointless.
There IS a case where executing code of "original" method would make sense.
And that palce is inside overriding method.
Notice that comments //(1) .. and //(2).. from put method of ItemBox and RedItemBox are quite similar. Actually they represent same action...
So it makes sense to reuse code from "original" method inside overriding method.
And that is possible via super.methodName(arguments) call (like from inside put of RedItemBox):
#Override
public void put(Item item){ //store only RED items
if (item.getColor()==Color.RED){
super.put(item); // <<<--- invoking code of `put` method
// from ItemBox (supertype)
}
}
beta obj = new beta();
Since you have created beta object , you cant refer directly to alphamethod1 of alpha object.
It can be modified as
class Beta extends Alpha
{
public void alphaMethod1()
{
super.alphaMethod1();
}
}
If I have a program that does the following:
if(input=='abc'){do x}
if(input=='def'){do y}
In the future, I may want to add another piece of code like so:
if(input=='ghy'){do x}
As you can see, I am adding a new 'if' statement for a different conditional BUT using the SAME function X.
The code in future has potential to have lots of different IF statements (or switches) all of which are comparing a string vs a string and then performing a function. Considering the future expansion, I was wondering if there is a possible 'neater', 'modular' way of achieving the same results.
It's a shame I can't combine the String with a Method call in a hashtable (String, method) in Java. That way I could just store any new procedures inside a hashtable and grab the relevant method for that String.
Any ideas?
Thank you
EDIT: Thank you for everyone's solutions. I was surprised by the quantity and quality of replies I received in such a small amount of time.
Maybe you can use enum. Example:
public enum InputType
{
abc, def
{
#Override
public void x()
{
System.out.println("Another method");
}
},
ghy;
public void x()
{
System.out.println("One method");
}
}
And further:
InputType.valueOf("abc").x();
Cheers!
I guess you could always use a Map<String, Runnable> and map to anonymous Runnable implementations:
myMap.put("abc", new Runnable() { public void run() { do x } });
...
myMap.get(input).run();
You should take a look at the command pattern. There are several ways of implementing it, and frameworks such as Spring can help you do with in a clean way.
But in a simple manner here's what you could do:
1-Create a Command interface with a method that your program will have to call to do the task, say doTask()
2-Create classes for command X and Y, implementing the Command interface.
3-Create a Map<String, Command> that will map your commands (X and Y) to logical names
4-Create a configuration file of your choice, say a .properties file that will map your input to your command names: abc=X, def=Y, ghi=X
5-Your program then does lookups on the config file to know which command to run according to the input.
A lot of ifs always tell us that we could do this better. In your case better option is to use design pattern e.g. Chain of responsibility. You will have good implementation which you can dynamic change and your code will be easier to maintenance than ifs implementation.
Take a look at this adaptation chain of responsibility to your case:
Main:
public static void main(String[] args) {
ClassA classA = new ClassA(Arrays.asList("abc", "ghi"));
ClassB classB = new ClassB(Arrays.asList("def"));
classA.setNextInChain(classB); // you can always write Builder to do this
String input = "def";
classA.execute(input);
}
BaseClass:
public abstract class BaseClass {
private Collection<String> patterns = Collections.EMPTY_LIST;
protected BaseClass nextInChain;
protected abstract void doMethod(); // your doA, doB methods
public void execute(String input) {
// this replace many ifs in your previous implementation
if (patterns.contains(input)) {
doMethod();
} else {
nextInChain.execute(input);
}
}
public void setPatterns(Collection<String> patterns) {
this.patterns = patterns;
}
public void setNextInChain(BaseClass nextInChain) {
this.nextInChain = nextInChain;
}
}
Class in chain:
public class ClassA extends BaseClass {
ClassA(Collection<String> patterns) {
setPatterns(patterns);
}
#Override
protected void doMethod() {
// do A
}
}
public class ClassB extends BaseClass {...}