I have a following superclass:
class FloatVector {
private List<Float> components;
public FloatVector(List<Float> comps)
{
components = comps;
}
public int getComponentCount(){
return components.size();
}
public float getComponent(int ind){
return components.get(ind);
}
//other methods
}
and I want to extend it to, for example, a 2D vector:
public class FloatVector2D extends FloatVector {
FloatVector2D(float x,float y)
{
List<Float> comps = new ArrayList<>();
comps.add(x);
comps.add(y);
super(comps);
}
}
but the IDE claims, that the superclass constructor must be the first call. There must be a way to implement the required behaviour.
super must be the first call in a constructor (if super is called).
You can simply replace your FloatVector2D constructor body with:
super(Arrays.asList(new Float[]{x,y}));
(and add the necessary imports)
Put super(comps); as first line in your FloatVector2D constructor.
Source: http://docs.oracle.com/javase/tutorial/java/IandI/super.html
"Invocation of a superclass constructor must be the first line in the subclass constructor."
Related
I have been reading about interface in java. Overall I understood the concept except one problem. In http://goo.gl/l5r69 (docs.oracle), in the note it is written that we can type cast an interface and a class implementing it. That is
public interface Relatable {
public int isLargerThan (Relatable other) ;
}
public class RectanglePlus implements Relatable {
public int width = 0;
public int height = 0;
public Point origin;
// four constructors
// ...
// a method for computing the area of the rectangle
public int getArea() {
return width * height;
}
// a method required to implement the Relatable interface
public int isLargerThan(Relatable other) {
RectanglePlus otherRect = (RectanglePlus) other;
if (this.getArea() < otherRect.getArea()) {
return -1;
} else if (this.getArea () > otherRect.getArea()) {
return 1;
} else {
return 0;
}
}
}
How can otherRect (which is a interface) be casted to a RectanglePlus. The confusion is, RectanglePlus is a class having variables, which are not present in the otherRect which is an interface
I have to admit that the example in the java doc you showed is simply bad and confusing.
It's bad because it contains an unsafe cast down the hierarchy.
It is always safe to cast up (from implementing class to interface/superclass), but casting down should be avoided when possible.
Ideally, the Relatable interface should also contain getArea() method:
public interface Relatable {
public int isLargerThan(Relatable other);
public int getArea();
}
Now you don't need the ugly cast, simply:
public int isLargerThan(Relatable other) {
if (this.getArea() < other.getArea()) {
return -1;
} else if (this.getArea () > other.getArea()) {
return 1;
} else {
return 0;
}
}
is enough. I also think that isLargerThan(Relatable other) is a bad name (larger in terms of what?). It should probably be something like hasBiggerArea(Relatable other) so that it explains what we are actually comparing (only "larger" is rather vogue).
Your interface is pretty similar to Comparable, (Are you sure Comparable isn't what your looking for?) so maybe you should add a generic to it:
public interface Relatable<T extends Relatable> {
public int isLargerThan(T t);
}
And then your class will start as:
public class RectanglePlus implements Relatable<RectanglePlus> {...
So your RectanglePlus instance will be compared with other RectanglesPlus elements only.
If this does not suit what you need, then you have to choose what will happen when you are comparing two different classes:
public class RectanglePlus implements Relatable {
public int width = 0;
public int height = 0;
public Point origin;
public int getArea() {
return width * height;
}
public int isLargerThan(Relatable other) {
if (!(other instanceof RectanglePlus)) {
return 1; // I'm bigger than any other class!
}
RectanglePlus otherRect =(RectanglePlus)other;
return this.getArea() - otherRect.getArea();
}
}
Or, a third option, you can add another method to your interface to obtain the measureable, realatable value of an object. Then you could add a default implementation to isLargerThan, if you are using Java 8:
public interface Relatable<T extends Relatable> {
public default int isLargerThan(T t) {
return this.getRelatableValue - t.getRelatableValue();
}
public int getRelatableValue();
}
In the method declaration public int isLargerThan(Relatable other){...} the parameter other is declared to be a reference to an object whose class implements the interface Relatable.
In the method body, the expression (RectanglePlus)other means to check that the object is of class RectanglePlus or a subclass of that (and throw a ClassCastException if it isn't). Now, a RectanglePlus is Relatable, but the inverse isn't necessarily true; the cast here ensures that other will either be RectanglePlus; if it's not further instructions will not be executed because an exception will have been thrown.
We can type cast any object(of class C) stored in a variable of type T1 (interface or class) into a variable of type T2 if T2 is a super class or super interface of class C or T2==C otherwise a ClassCastException will be thrown.
So in your case if an object obj of class Foo implements Relatable is passed to isLargerThan method then it will throw ClassCastException, because obj's class Foo is not a super class of RectanglePlus.
One aspect that hasn't been touched on in other answers is the fact that the example in the Oracle docs has a clear problem: if Relatable is only meant to be analogous to Comparable, then there needs to be a specialization for shapes in order to avoid the cast in the isLargerThan method. Perhaps, for example, an interface called RelatableShape, which itself extends Relatable, and provides for the getArea() method. Then, you could have Circle, Hexagon, Rectangle, etc. classes that implement RelatableShape (the interface with isLargerThan and getArea), and the isLargerThan() method would not need to cast its argument to a particular concrete class (since the parameter could be guaranteed to implement RelatableShape, and getArea() would always be available).
Thus, though the Oracle documentation is showing something that is valid Java, it's also showing something that's necessary because of a bad design. Keep that in mind. Casting is almost never necessary in real code.
It's rather simple your mehtod
public int isLargerThan(Relatable other)
just asks for an argument that implements Relatable. It could be an object of any class that implements Relatable. As long as there is something like
public class SomeName implements Relatable { /* Implementation */ }
in the class, you can treat objects of that class as Relatable.
But that does not mean that these objects are not of their own type. If you have the following classes
public class Square implements Relatable {
public int isLargerThan(Relatable other) {
// Implementation
}
// Square specific implementation
}
and
public class Rectangle implements Relatable {
public int isLargerThan(Relatable other) {
// implmentation
}
// Rectangle specific implemenation
}
you can call the interface methods like this:
/* ... */
public static int check(Relatable a, Relatable b) {
return a.isLargerThan(b);
}
/* ... */
Square s = new Square();
Rectangle r = new Rectangle();
System.out.println("Check: " + check(s, r));
ATTENTION:
Because several different classes can implement Relatable you have to check the type of the argument to isLargerThan, otherwise you run into type cast exceptions.
Maybe you can specify something like this in Relatable
public int getSize();
Than you could write your isLargeThan method like this:
public int isLargerThan(Relatable other) {
if (this.getSize() < other.getSize())
return -1;
else if (this.getSize() > other.getSize())
return 1;
else
return 0;
}
Then there would be no need for a type cast.
I know that we can skip casting by adding using the Generics in java as follows. (When we are using it outside of the Generic class.)
But if we are doing some logics on the type object (T item) inside the generic class (Container<T>) we should check the instance of and specially cast isn't it? So we can use it to skip casting out side the generic classes.
Please check the commented code in the public void setItem(T item) method.
I want to know whether my understanding is correct or am I missing something
Client.java
public class Client {
public static void main(String[] args) {
// String container
Container<String> stringContainer = new Container<String>();
stringContainer.setItem("Test");
//stringContainer.setItem(new StringBuffer("")); // compilation error, type safety checking
System.out.println(stringContainer.getItem().toUpperCase()); // No need to cast
// Integer container
Container<Integer> integerContainer = new Container<Integer>();
integerContainer.setItem(123);
//integerContainer.setItem("123"); // compilation error, type safety checking
System.out.println(integerContainer.getItem().intValue()); // No need to cast
}
}
Container class
class Container<T> {
private T item;
public T getItem(){
return item;
}
public void setItem(T item){
/* If I' doing some thing on item then I have to check the instance of and cast isn't it?
if(item instanceof String){
System.out.println("setItem().((String)item).toUpperCase() : " + ((String) item).toUpperCase());
}
*/
this.item = item;
}
}
Reference : http://nandirx.wordpress.com/category/java-2/generics-java/
As others have said, you shouldn't ever downcast a generic type as it defeats the purpose of generics.
You should use bound generics instead. A bound generics allows you to require a generic be of a specific type. This allows you to access values in the specific type without needing to cast.
This doesn't make sense with the String class as String is marked final and so cannot be extended, but for the future, try something like this.
public interface Shape{
double getArea();
}
public class Rectangle implements Shape{
double width;
double height;
public double getArea(){ return width*height;}
}
//this collection can hold Shape, or any type implementing shape.
public class MyShapeCollection<T extends Shape>{
List<T> shapes;
public double getAreaSum(){
double areaSum = 0;
for(Shape s : shapes){
areaSum += s.getArea();
}
return areaSum;
}
}
public static void main(String[] args){
MyShapeCollection<Rectangle> rectangles = new MyShapeCollection<Rectangle>();
//bad code monkey. String does not implement Shape!
//this line won't compile. including it for demonstration purposes.
MyShapeCollection<String> willNotCompile = new MyShapeCollection<String>();
}
If your collection will only hold strings, you don't need generics.
Yes, your understanding is correct.
Adding type specific code here, however, defeats the purpose of generics.
A better solution would be the following.
Client.java
public class Client {
public static void main(String[] args) {
// String container
Container<String> stringContainer = new StringContainer();
stringContainer.setItem("Test");
//stringContainer.setItem(new StringBuffer("")); // compilation error, type safety checking
System.out.println(stringContainer.getItem().toUpperCase()); // No need to cast
}
}
Container.java
class Container<T> {
private T item;
public T getItem(){
return item;
}
public void setItem(T item){
this.item = item;
}
}
StringContainer.java
class StringContainer extends Container<String> {
#Override
public void setItem(String item){
System.out.println( item.toUpperCase() );
super.setItem( item );
}
}
Right, or you could overload the setItem() method for different types of parameters, but that's actually even worse.
Yes, for your case casting is necessary. Because you are using string functions specifically.
But its like you are not using generic feature.
If you wanna to print item, then you can override toString() method of each item, and you can directly put item object in sysout(). By doing so, there will be no casting needed and all code get generic for all items.
What you say here.
I am seeing the following kind of code repeatedly in Mapreduce programs. This is just a snippet of code taken out. The entire code is available here
what does the super call in the constructor do? Does it call the constructor of IntPair.class? why is such a call necessary.
public static class KeyComparator extends WritableComparator {
protected KeyComparator() {
super(IntPair.class, true);
}
#Override
public int compare(WritableComparable w1, WritableComparable w2) {
IntPair ip1 = (IntPair) w1;
IntPair ip2 = (IntPair) w2;
int cmp = IntPair.compare(ip1.getFirst(), ip2.getFirst());
if (cmp != 0) {
return cmp;
}
return -IntPair.compare(ip1.getSecond(), ip2.getSecond()); //reverse
}
}
super(), when used in the constructor will call the constructor of the class which is extended. In this case, it will call the WriteableComparator constructor. You can see more details on super in the java documentation here:
Java super link
In particular, see the section titled "Subclass Constructors".
Does it call the constructor of IntPair.class?
No, It's just a argument that is passed in the super class constructor.
why is such a call necessary?
To avoid the call of no arguments constructor of the super class that is by default added by the compiler.
If there are multiple constructors in the super class then you can be specified which constructor of the super class should be called based on arguments.
Sample code: (Look at the output when KeyComparator object is created)
class WritableComparator {
public WritableComparator(){
System.out.println("default constructor is called");
}
public WritableComparator(Class<?> clazz, boolean flag) {
System.out.println("two arguemnts constructor is called");
}
}
class KeyComparator extends WritableComparator {
public KeyComparator() {
//super(); // by default added by the compiler
super(IntPair.class, true);
}
}
IntPair.class notation is used to get object describing this class. Like here:
Class<?> type = Integer.class;
This type variable is not an instance of Integer class, but instance of object describing Integer type.
Some classes requires you to pass them type of objects you want them to work with. Then, they can for example create new instances of those classes, using this type object.
more about Class class
This is a problem I've been working on for a little while now and I've barely made any progress. I've been running into a lot of problems trying to use an abstract class when extending ArrayList.
My first step was to define three classes, Circle, Rectangle, and Triangle that are all concrete subclasses of an abstract class GeometricObject. The base class has abstract methods getArea() and getPerimeter() that are overridden in the subclasses by the specific getPerimeter() and getArea() formula for that particular object. This part is completed and is working as intended.
The next part is where I'm having trouble. I'm supposed to define a new class GeoemetricObjectList that extends ArrayList<GeometricObject>. This class should override the add(), remove(), and clear() methods. This class keeps a totalArea and totalPerimeter variable of the objects on the list.
Right now I've created a, quite frankly, messy if statement list in my GeometricObjectList add() method that I'd like to clean up. Here is my code for that class so far:
import java.util.ArrayList;
#SuppressWarnings("hiding")
public class GeometricObjectList<GeometricObject> extends ArrayList<GeometricObject>{
final static long serialVersionUID = 1L;
public double totalArea = 0;
public double totalPerimeter = 0;
public boolean add(GeometricObject element){
if(element instanceof Rectangle) {
totalArea += ((Rectangle)element).getArea();
totalPerimeter += ((Rectangle)element).getPerimeter();
}
if(element instanceof Circle) {
totalArea += ((Circle)element).getArea();
totalPerimeter += ((Circle)element).getArea();
}
if(element instanceof Triangle) {
totalArea += ((Triangle)element).getArea();
totalPerimeter +=((Triangle)element).getArea();
}
return super.add(element);
}
public boolean remove(GoemetricObject element) {
return super.remove(element);
}
public void clear() {
}
}
When I simply write totalArea += element.getArea() I get the error "The method getArea() is undefined for the type GeometricObject but in my GeometricObject class I have a public abstract getArea() that is overridden by the getArea() method in each concrete (Triangle, Circle, Rectangle) class.
My next issue is with the remove() method in GeometricObjectList. It looks like this:
public boolean remove(GeometricObject element) {
return super.remove(element);
}
I am getting the error "Name clash: The method remove(GeometricObject) of type GeometricObjectList<GeometricObject> has the same erasure as remove(Object) of type ArrayList but does not override it". I never received this error when creating the add() method.
Any help with this is REALLY greatly appreciated. If there's any more info you need ask for it and I'll have it up in a second!
You really had several different issues - including spelling and hiding,
// Make sure you have these methods in your GeometricObject.
// private static abstract class GeometricObject {
// public abstract double getArea();
// public abstract double getPerimiter();
// }
// Do not use that annotation. It was warning you!
public class GeometricObjectList extends
ArrayList<GeometricObject> {
final static long serialVersionUID = 1L;
public double totalArea = 0;
public double totalPerimeter = 0;
public boolean add(GeometricObject element) {
if (element != null && super.add(element)) {
totalArea += element.getArea(); // add area
totalPerimeter += element.getPerimiter(); // add perimeter
return true;
}
return false;
}
public boolean remove(GeometricObject element) { // Spelling!
if (element != null && super.remove(element)) {
totalArea -= element.getArea(); // subtract area
totalPerimeter -= element.getPerimiter(); // subtract perimeter
return true;
}
return false;
}
public void clear() {
super.clear();
}
}
Well, let's start with first things first.
This class declaration isn't doing what you believe it's doing:
public class GeometricObjectList<GeometricObject> extends ArrayList<GeometricObject>
Java is treating GeometricObject as a type parameter. If you want to bound the generic strictly to only instances of a GeometricObject, change that signature to this:
public class GeometricObjectList<T extends GeometricObject> extends ArrayList<T>
Then Java will identify the type parameter T to only be instances of GeometricObject and its children.
You could also eschew the need for the generic type argument altogether and have your ArrayList tightly bound to GeometricObject without a generic:
public class GeometricObjectList extends ArrayList<GeometricObject>
Next, the signature of add gets to change. Since T is already bound to be an instance of GeometricObject, we don't need to explicitly say that's what we're adding.
public boolean add(T element)
If you elected not to use T, then you would keep your signature the same.
In either case, the casts also become redundant and can go away.
Finally, your remove method isn't overriding the inherited remove - it needs to match the signature as well.
public boolean remove(Object element)
I have read a book and it says I can override a method if it has the same signature. according to the book the signature of a method is Method_Name + Parameters passed.
as per the book, i can override a method which has different return types. Is it actually possible to override a method with different return type in Java? because i have done a some search on the net i found people saying that to override a method the return type should be same as well.
according to the book it also says the java will throw a compile error when we try to overload a method with same method name and parameters but different return types since the signature means only the method name and parameters. If this is true, we should be able to override a method with different return type.
Please help me to understand this. Thanks in advance.
You can return a different type, as long as it's compatible with the return type of the overridden method. Compatible means: it's a subclass, sub-interface, or implementation of the class or interface returned by the overridden method.
And that's logical. If a method returns an Animal, and your derived class returns a Cow, you're not breaking the contract of the superclass method, since a Cow is an Animal. If the derived class returns a Banana, that isn't correct anymore, since a Banana is not an Animal.
Your parent class has made a promise to the outside world. For example, the method:
public Price calculatePrice(Items[] items).
It tells the world to expect a Price.
If you enhance that functionality in your subclass, you still have to keep your parent classes' original promises for it.
You can add overloaded ways of calculating:
public Price calculatePrice(Items[] items, Integer minimumCharge).
You can even improve your parent's promises by using a MORE specific return type:
public AccuratePrice calculatePrice(Items[] items, Integer minimumCharge).
But you must return at least the type that your parent promised.
The same goes for Exceptions in the method declaration too.
Yes, it is possible since Java 5, it is called covariant return type. The return type should be a subcass of super class method return type (primitive types are not allowed). Example
class X implements Cloneable {
#Override
protected X clone() {
try {
return (X) super.clone();
} catch (CloneNotSupportedException e) {
throw new Error(e); // can never happen
}
}
}
Here is an example:
class Base {
public Number test() {
return 0;
}
}
class A extends Base {
public Long test() {
return 1L;
}
}
Your overriden method can have same type or the sub-type of the
original return type which is called as covariant return.
If you change the return type of the overriden method to something else which is not a sub-type of the original type, then you'd get a compile time error.
Yes we can override different return types but they should be subclass.
public class Shape {
public Shape area(Integer i) {
System.out.println("Sape Area");
System.out.println("Integer");
return null;
}
}
package com.oops;
public class Circle extends Shape {
public Circle area(Integer i) {
System.out.println("Circle Area");
System.out.println("int");
return null;
}
}
// Covariant Overriding
public class Parent {
public Parent(){}
String parentName;
public Parent(String parentName){
this.parentName=parentName;
System.out.println(this.parentName);
}
public Parent show(){
return new Parent("Parent");
}
}
public class Child extends Parent{
public Child(){}
String name;
public Child(String name){
this.name=name;
System.out.println(this.name);
}
public Child show(){
return new Child("Child");
}
}
public class Main {
public static void main(String[] args) {
Parent parent=new Child();
parent.show();
Parent parent1=new Parent();
parent1.show();
}
}