What is the real reason that in Java, and similar languages, must be explicitly said that a class implements an interface?
Imagine implicit implementation:
interface Flyer { void fly(); }
public class Duck { public void fly() {...} }
public class Plane { public void fly() {...} }
public class Hoe { void hangAround() {...} }
void startFlying(Flyer flyer) {...}
void race() {
...
startFlying(duck); // OK
startFlying(plane); // OK
startFlying(hoe); // Compilation error.
}
Compiler knows method's signatures, return type (and modifier, of course). At this point it seems clear that there is no need to explicitly specify that Duck and Plane implements Flyer.
I would said that "implements XYZ" may be removed from Java without worries.
No difference, check at compilation time so it's OK.
In the other hand:
#JBNizet mentioned different meaning of methods with the same signature and return type.
I will use his example:
interface Runner { void run(); }
public class Guy { public void run(); }
public class Gal { public void run(); }
void startRunning(Runner r) {...}
void race() {
startRunning(guy); // OK
startRunning(gal); // OK
startRunning(runnableThread); // OK
}
OK for compiler, OK for startRunning() (OK for me). It's up to your philosophy if this is OK for you or not.
Explicit:
public class Guy **implements Runner **{ public void run(); }
public class Gal **implements Runner **{ public void run(); }
In bold (or text between ** and **) is the price which you must pay for
void race() {
startRunning(guy); // OK
startRunning(gal); // OK
startRunning(runnableThread); // Compilation error!
}
Note compilation error so you can see the issue before testing.
If it's intended to use runnableThread in startRunning() as well you must do it even more explicitly (enough time to realize what you are doing).
"I wondered how much of time is wasted by resolving issues related to typing "implements XYZ" compared to time wasted by resolving issues with implicitly implemented interfaces. If it's way more better for implicitly implemented interface then I hate Java designers for their decision and that they force us to belive it's better :-)"
Ladybug and airbus (and duck)
I think the issue with implicitly implemented interface is only theoretical and rare in real.
public class Airbus {
void takeOff() {...}
void land() {...}
Passenger[] getPassengers() {...}
}
public class Ladybug {
void takeOff() {...}
void land() {...}
}
public class Duck {
void takeOff() {...}
void land() {...}
Passenger[] getPassengers() {...}
}
public interface Aircraft {
void takeOff();
void land();
Passenger[] getPassengers();
}
public void fly(Aircraft aircraft) {
aircraft.takeOff();
for (Passenger p : aircraft.getPassengers()) {...}
aircraft.land();
}
public void airport() {
fly(airbus_a380); // OK
fly(ladybug); // Compilation error, does not match Aircraft requirements.
fly(duck); // OK
}
public interface Lander {
void land();
}
public void landAtMeadow(Lander lander) {...}
public void meadow() {
landAtMeadow(airbus_a380); // OK
landAtMeadow(duck); // OK
landAtMeadow(ladybug); // OK
}
All of them are matching requirements of landAtMeadow so they can be used in that context. Even it may not be possible to land at meadow for airbus_a380 (In other word testing is required) you need to land there in emergency.
Do not forget that landAtMeadow() may have more specific requirements like
public interface Lander { void landAtLimitedArea(int size); }
to say that the space is limited, so if airbus_a380 does not support this method then you have compilation error here.
Java is a strong typed language, so the assignation of an instance to an interface typed variable must be validated at compile time. This can only be done by explicitly declared interface implementations.
As others have said, this is a basic characteristic of the Java language. It's there for good reasons, folks who are doing serious largescale programming like it, and there's absolutely no reason to change it.
If it bothers you, I strongly recommend that you find another language that is more weakly typed and use that instead. There are a fair number of languages these days which can be compiled into Java bytecodes and used in a Java environment, so you might not even have to give up the flexibility of being able to run in a JVM.
My friend In a strongly typed languages, for ex: in C or Java, when a variable or reference is declared, it must be informed to the compiler what data type the variable or reference is of
When a class is declared to implement an interface X then any other method working with interface X is sure that all the necessary methods are implemented in the class (and therefore they do not need to check every time if needed method is implemented). If there was no such declaration, then any method using classes which implement X would need to:
ensure that the class of object whith which the method is working implements all methods necessary (so go through all the methods of the class searching the ones you want every time you expect to work with interface X - instead of doing this once, at compilation).
have many error handling lines of code implemented (what to do, if I expect method A to do something, but method A it is not there at all?)
Static typing adds much to code's safety in general, as many errors are possible to detect at compilation. Why try to change Java from staticaly to dynamicaly typed? There are many dynamicaly typed languages out there, with their pluses and minuses, ready to use (Python, for example).
Related
Code for illustration:
public Interface FlightBehaviour {
void fly();
}
public class Fly implements FlightBehaviour {
#Override
public void fly() throws CrashWithObject {
// does something to fly
}
}
public class CanNotFly implements FlightBehaviour {
#Override
public void fly() {
// does not fly
}
}
public class Bird() {
private FlightBehaviour fly;
public void setFlightBehaviour(FlightBehaviour flightBehaviour) {
this.car = car;
}
#Override
public void fly() throws CrashWithObject {
car.fly();
}
}
JUnit:
#Test
public void testFlighBehaviourOfNonFlyingBird() {
// ...
Bird plasticDuck = new Bird();
plasticDuck.setFlightBehaviour(new CanNotFly());
plasticDuck.fly(); //Compiler shows that an Exception is thrown
// However, I know that this will never happen since my Bird can't fly
// and therefore never throws an exception
// ...
}
This is a simple replication of my implementation. I'm using the strategy pattern as you can see.
My Question is: How can I suppress the warning that is given?
In a test case, you shouldn't assume that the exception can't be thrown, but instead test that (by making the test fail in case of an exception, maybe after trying to provoke it).
With your (strategy pattern based) code structure, it's close to impossible for the compiler to deduce that no exception will be thrown. We as humans already face a hard job with that reasoning (ignoring a few typos in your code):
The Bird.fly() method only throws CrashWithObject if fly.fly() does.
fly has been most recently been set to be a CannotFly in plasticDuck.setFlightBehaviour(new CanNotFly());.
CannotFly.fly() does not throw CrashWithObject.
Probably, setFlightBehaviour() isn't called anywhere else for this Bird instance, but that needs a thorough analysis of the complete application to be really sure about that.
So we expect the fly field still to hold an instance of CannotFly at the time of the plasticDuck.fly() call, which allows us to conclude that no CrashWithObject can be thrown.
You see, it needs a lot of non-trivial reasoning across various code snippets to come to the no-exception conclusion, a depth of reasoning that I don't expect to see in a compiler anytime soon.
The problem is best explained with the following code:
public class TemplateClass {
public void templateOne() {
checkConditionA();
primitiveOp1();
checkConditionB();
}
public void templateTwo() {
checkConditionA();
primitiveOp2();
checkConditionB();
}
protected abstract void primitiveOp1();
protected abstract void primitiveOp2();
// rest of the methods
}
Now I have code duplication with templateOne() and templateTwo(), but I would like to have just one template method but with interchangeable primitive operations.
What you want is, in essence, a guard block around a method call. DRY programming is good practice, but be advice that you do not wawnt to couple what should not be coupled. I would only couple those two methods if it is guaranteed that they must always be guarded by the same pre- and postcondition(s).
If this is the case, I would recommend to implement a method private void callWithChecks(Runnable primitiveOperation) and then pass the respective primitive operation as parameter to this method:
public abstract class TemplateClass {
public void templateOne() {
callWithChecks(this::primitiveOp1);
}
public void templateTwo() {
callWithChecks(this::primitiveOp2);
}
private void callWithCkecks(Runnable primitiveOperation) {
checkConditionA();
primitiveOperation.run();
checkConditionB();
}
protected abstract void primitiveOp1();
protected abstract void primitiveOp2();
// rest of the methods
}
If you do not want to use the function interface Runnable, you can of course define your own interface. I went with it, since it is a Java base class.
Two remarks on your code:
TempalteClass must be declared abstract, otherwise the code will not compile
If you intend to implement methods checkConditionA() and checkConditionB() within TemplateClass, I would recommend defining them as private or final such that they cannot be overridden.
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
This is a question from this book: https://www.cl.cam.ac.uk/teaching/0506/ConcSys/cs_a-2005.pdf page 28
Can you write an additional Java class which creates an
object that, when passed to the test method causes it to
print “Here!”? As I say in the code, editing the class A
itself, or using library features like reflection, serialization,
or native methods are considered cheating! I’ll provide
some hints in lectures if nobody can spot it in a week or
so. None of the PhD students has got it yet.
public class A {
// Private constructor tries to prevent A
// from being instantiated outside this
// class definition
//
// Using reflection is cheating :-)
private A() {
}
// ’test’ method checks whether the caller has
// been able to create an instance of the ’A’
// class. Can this be done even though the
// constructor is private?
public static void test(Object o) {
if (o instanceof A) {
System.out.println("Here!");
}
}
}
I know the question is a lot unclear. I can think of many different 'hack-ish' solutions but not sure if they will be counted as 'cheating' or not :)
I can't find the official answer so asking you for what would be a good answer.
If we consider that nesting class A does not "modify it" (as, technically, all lines of code are intact) then this solution is probably the only valid option:
class B
{
static
public class A {
// Private constructor tries to prevent A
// from being instantiated outside this
// class definition
//
// Using reflection is cheating :-)
private A() {
}
// ’test’ method checks whether the caller has
// been able to create an instance of the ’A’
// class. Can this be done even though the
// constructor is private?
public static void test(Object o) {
if (o instanceof A) {
System.out.println("Here!");
}
}
}
public static void main (String[] args) throws java.lang.Exception
{
A.test(new A());
}
}
What I mean is, technically it follows all the rules:
Can you write an additional Java class which creates an object that, when passed to the test method causes it to print “Here!”? - Done
As I say in the code, editing the class A itself ... considered cheating! - Technically, the class is unedited. I copy pasted it into my code.
... or using library features like reflection, serialization, or native methods are considered cheating! - Done
If, however, you decide that nesting class A should not be allowed, then I believe there is no proper solution to the problem given the current definition. Also, given the section of the book this task is given in, I bet that the author wanted to make the constructor protected but not private.
Somehow, I don't like this sort of questions. It's from a lecture back in 2005, and according to websearches, it seems that nobody has found "the" solution until now, and no solution has been published.
The constraints are clear, but the question of what is allowed or not is somewhat fuzzy. Every solution could be considered as "cheating", in one or the other way, because a class with a private constructor is not meant to be subclassed. That's a critical security mechanism, and the responsible engineers are working hard to make sure that this security mechanism cannot be trivially circumvented.
So of course, you have to cheat in order to solve this.
Nevertheless, I spent quite a while with this, and here's how I eventually cheated it:
1.) Download the Apache Bytecode Engineering Library, and place the bcel-6.0.jar in one directory.
2.) Create a file CreateB.java in the same directory, with the following contents:
import java.io.FileOutputStream;
import org.apache.bcel.Const;
import org.apache.bcel.generic.*;
public class CreateB
{
public static void main(String[] args) throws Exception
{
ClassGen cg = new ClassGen("B", "A", "B.java",
Const.ACC_PUBLIC | Const.ACC_SUPER, new String[] {});
ConstantPoolGen cp = cg.getConstantPool();
InstructionList il = new InstructionList();
MethodGen method = new MethodGen(Const.ACC_PUBLIC, Type.VOID,
Type.NO_ARGS, new String[] {}, "<init>", "B", il, cp);
il.append(InstructionFactory.createReturn(Type.VOID));
method.setMaxStack();
method.setMaxLocals();
cg.addMethod(method.getMethod());
il.dispose();
cg.getJavaClass().dump(new FileOutputStream("B.class"));
}
}
3.) Compile and execute this class:
javac -cp .;bcel-6.0.jar CreateB.java
java -cp .;bcel-6.0.jar CreateB
(note: On linux, the ; must be a :). The result will be a file B.class.
4.) Copy the class that was given in the question (verbatim - without any modification) into the same directory and compile it.
5.) Create the following class in the same directory, and compile it:
public class TestA
{
public static void main(String[] args)
{
A.test(new B());
}
}
6.) The crucial step: Call
java -Xverify:none TestA
The output will be Here!.
The key point is that the CreateB class creates a class B that extends A, but does not invoke the super constructor. (Note that an implicit super constructor invocation would normally be added by the compiler. But there's no compiler involved here. The bytecode is created manually). All this would usually fail with a VerifyError when the class is loaded, but this verification can be switched off with -Xverify:none.
So in summary:
The class A itself is not edited (and also its byte code is not edited, I hope this is clear!)
No reflection
No serialization
No custom native methods
There are a few options here:
Create a class:
public class Y extends A {
public static void main(String[] args) throws Exception {
X.test(new Y());
}
}
And then edit the bytecode and remove the call to X.. Of course this violates the JVM specification and has to be run with -Xverify:none as said above. This is essentially the same as the one #Marco13.
Option 2:
import sun.misc.Unsafe;
public class Y extends A {
public static void main(String[] args) throws Exception {
Unsafe uf = Unsafe.getUnsafe();
X.test((X) uf.allocateInstance(X.class));
}
}
Compile the code and run it by putting your classpath in the sysloader (otherwise it won't work):
$ java -Xbootclasspath/p:. Y
Both work for me :) Of course, they are both cheating. The first option isn't Java. The second is, well, evil :)
If I find out another way, I'll post it :)
In any case this can't be done without low-level tricks. The JVM Specification explicitly prohibits the creation of an object without calling the constructor as the object in the stack is uninitialized. And the JVM Specification explicitly prohibits not calling the super constructor. And the JVM Specification explicitly requires verification of access protection.
Still funny, though :)
Java can support unicode class name:)
The A in "if (o instanceof A)" could be different from the A in "public class A"
For example, the code below will print "Here!" instead of "bad".
A.java
public class A {
// Private constructor tries to prevent A
// from being instantiated outside this
// class definition
//
// Using reflection is cheating :-)
private A() {
// A: U+0041
}
// ’test’ method checks whether the caller has
// been able to create an instance of the ’A’
// class. Can this be done even though the
// constructor is private?
public static void test(Object o) {
if (o instanceof А) {
System.out.println("Here!");
}
}
}
А.java
public class А {
// A: U+0410, not A: U+0041
}
Main.java
public class Main {
public static void main(String[] args) {
A.test(new А());
}
}
Suppose we have some Base class with a method with Object parameter, and in a newer vesion developers decide to change Ojbect to int.
for example:
public class Base {
public void foo(Object i)
{
System.out.println("ahahaa");
}
}
public class Child extends Base
{
public void foo(Object i)
{
System.out.println("tru-la-la");
}
}
Then new version of Base:
public class Base
{
public void foo(int i)
{
Console.WriteLine("ahahaa");
}
}
Then if we call something like:
Child child = new Child();
child.foo(5);
We'll get "ahaha" instead of expected "tru-la-la"
So how can we deal with it, and what architecture solution should we use?
It seems you are not looking for an explanation regarding why you get "ahaha" and not "tru-la-la" (which you used to get before the change in the Base class).
If you are releasing libraries to be used by other developers, you are expected to maintain backward comptibility. The chnage you describe in the Base class clearly doesn't respect backward comptibility, so any code that relies on it would break.
There's nothing you can do other than change your code or stop using that library.
You can change your code, for example, by calling child.foo(new Integer(5)), which would invoke the sub-class method.
Another thing that can help is to mark the method in the Child class with #Override annotation. This would stop your code from compiling after the change in the Base class.
If you are using an int -child.foo(5); then the JVM will naturaly take the method in the child object that is most specific. In this case it is
a choice between
public void foo (Object i) {
&
public void foo (int i) {
the more specific is --
public void foo(int i) {
which writes "ahahaa"