why compilation fails for that example - java

I was working on SCJP6 dumps when I found this confusing exercise:
Given classes defined in two different files:
package packageA;
public class Message {
String getText() { return “text”; }
}
And:
package packageB;
public class XMLMessage extends packageA.Message {
String getText() { return “<msg>text</msg>”;}
public static void main(String[] args) {
System.out.println(new XMLMessage().getText());
}
}
What is the result of executing XMLMessage.main?
A. text
B. Compilation fails.
C. <msg>text</msg>
D. An exception is thrown at runtime.
The answer was: B, but I don't understand why; I think the answer should be C.

If the code you posted it's the one that is in the book, the correct answer as you mentioned is C, let me explain why.
Again, assuming you copied the code as it's shown in the book when you do, the following line:
String getText() { return “<msg>text</msg>”;}
Its not overriding the getText() method in packageA.Message class but declaring a new one, that will can be accessed for XMLMessage instances within packageB.
This would be different if the the main method is something like:
public static void main(String[] args) {
Message message = new XmlMessage();
System.out.println(message.getText());
}
In this case there is a compilation error since the Message.getText() methods is not exposed outside the package.

A package default method cannot be overridden because it is not visible in another package.
In your example, method getText() in class Message is only visible to members of packageA.
Method does not override package visible method in Eclipse

The method String getText() { return “text”; } is with package (default) scope . And hence it is not visible outside the package packageA .
so it is not possible to override the method in the class XMLMessage which is outside the packageA .
You can learn the basics of method overloading and overriding here

Related

Constructor behaving like a method

I'm new to Java so not really sure if it's an error on my part. My project has two packages within. I'm trying to use an object belonging to a class of package lovo in an object of a class of package j2. The constructor of object belonging to package lovo is now being treated as a method. Why is that?
package j2;
import lovo.kulo;
public class J2
{
public static void main(String[] args)
{
kulo kla ;
kla = new kulo();
//kla.kulo();
}
}
package lovo;
public class kulo {
public void kulo(){
System.out.print("This is supposed to be a constructor");}
}
When i run there is no output, however when i remove the comment and add it as code there is an output. Since it's a constructor shouldn't it print as soon as the object is created?
It is indeed a method. To make it a constructor, remove the void return type. It'll also be less confusing if you follow Java naming conventions and begin class names (and therefore constructor names) with an uppercase letter.

Java package-only variables and inheritance

I have these two classes in different packages(named a and b)
package a;
import b.*;
public class Tree
{
int health = 100;
public void show()
{
System.out.println(this.health);
}
public static void main(String[] args)
{
Arb c = new Arb();
//System.out.println(c.health); is not visible
c.show();
}
}
package b;
import a.*;
public class Arb extends Tree
{
}
I know that field health can't be accesed by an instance of type Arb because is not visible,so it doesn't exist for an instance of Arb. All that it inherited is the public void show() method. Ok until now.
But from my tests, calling method show through object c outputs the answer 100,as the initial value for a Tree object.
My problem with understanding this is: The method calls this.health ,so as long as object c calls this method, this = c. But health shouldn't be visible...
Could someone explain what is actually happening there? Thank you!
Your statement "so it doesn't exist" is incorrect. It exists, it's just not visible.
An instance of Arb is also an instance of Tree, and code in Tree can see the field, while code in Arb cannot see it.
As you correctly said, the Arb class inherits the public show() method of the Tree class. When calling the method show() of the class Arb you are actually calling the show() method in Tree. Because this method can see the field health it can also print it's value.

Java changing variable name changes program behaviour

I found a scenario where java program behaves differently after renaming a variable. I understand this isn't actually code that anyone would use but if someone knows whats going on it would be nice to have an explanation. I tried this with java 1.6 on Eclipse Kepler.
package _test;
public class TestClass{
public static void main(String...args){
Object testClazz$1 = new Object (){
public String toString() {
return "hello";
}
};
TestClass$1 test = new TestClass$1();
System.out.println(testClazz$1.toString());
test.doStuff();
}
}
class TestClass$1{
public void doStuff(){
System.out.println("hello2");
}
}
This outputs:
hello
Exception in thread "main" java.lang.NoSuchMethodError:
_test.TestClass$1.doStuff()V at _test.TestClass.main(TestClass.java:13)
As far as I understand the compiler creates a TestClass$1.class file for the testClazz$1 object and this causes a naming collision.
But after renaming the object to testClass$1:
package _test;
public class TestClass{
public static void main(String...args){
Object testClass$1 = new Object (){
public String toString() {
return "hello";
}
};
TestClass$1 test = new TestClass$1();
System.out.println(testClass$1.toString());
test.doStuff();
}
}
class TestClass$1{
public void doStuff(){
System.out.println("hello2");
}
}
The output is:
_test.TestClass$1#2e6e1408
hello2
Any ideas what is going on here?
Anonymous classes are named automatically by appending a $ sign and an increasing number to the name of the enclosing class.
In your first example the anoymous class will be named TestClass$1 which has no doStuff() method, you only override toString() that's why you get NoSuchMethodError error.
In your 2nd example you already have a local variable named TestClass$1, so the auto-generated name chosen by the compiler will be a different name, most likely TestClass$2. Since you instantiate TestClass$1 which is not an anonymous class but a class explicitly defined by you, that will be instantiated which has a doStuff() method which properly prints "hello2" and which does not override Object.toString() so printing the value returned by its toString() method will print the default value as specified in java.lang.Ojbect (which is the class name appended with a # sign followed by the default hash code in hexadecimal format).
Conclusion: While this is an interesting example, you should never use the $ sign in your class names and in identifier names.
When the classloader encounters the anonymous Object() {...} class it loads it under the name TestClass$1. This creates a conflict with class TestClass$1 {...} which was explicitly defined.
However, class name conflicts are handled rather ungracefully. This bit of documentation tells us that
If the class c has already been linked, then this method simply returns.
That's what happens in your case. You only ever load one of the two TestClass$1 classes.
The "different variable names" are not responsible for anything other than re-compiling and re-linking within your compiler. At this point, the classloader is free to pick whichever one of the two TestClass$1 likes better and use that everywhere.
If you're using something like eclipse (like I am) then your bytecode will get cached, until a new touch operation on the source file (and updating of timestamps...). Here's what I did to reproduce (running openjdk 1.7, Eclipse Kepler under RedHat):
Put this inside a source file TestClass.java:
package javaclasses.classes;
public class TestClass{
public static void main(String...args){
Object o = new Object (){
public String toString() {
return "hello";
}
};
TestClass$1 test = new TestClass$1();
System.out.println(o.toString());
test.doStuff();
}
}
class TestClass$1{
public void doStuff(){
System.out.println("hello2");
}
}
ctrl + F11 outputs:
javaclasses.classes.TestClass$1#42293b53
hello2
Open this in a console and touch TestClass.java
Go back in eclipse and ctrl + F11 now outputs:
hello
Exception in thread "main" java.lang.NoSuchMethodError: javaclasses.classes.TestClass$1.doStuff()V
at javaclasses.classes.TestClass.main(TestClass.java:13)
Conlusion: All that can be said definitively is that the default ClassLoader is unreliable for manually resolving classes with the same fully qualified names. Changing variable names doesn't matter, the updated timestamp on your source file does.
I modified your code to remove the "$" from the class names and renamed testClass$1 to t and changed the println slightly as follows:
public class TestClass{
public static void main(String...args){
Object t = new Object (){
public String toString() {
return "t.toString()";
}
};
TestClass1 tc1 = new TestClass1();
System.out.println(t.toString());
tc1.doStuff();
}
}
class TestClass1{
public void doStuff(){
System.out.println("TestClass1.doStuff()");
}
}
Output is now:
t.toString()
TestClass1.doStuff()
Is this what you expect?

Java/Android: Method with Full Project Scope

I have a method that I've created that I would like to be able to use anywhere, but I don't know what the best practice is for giving access to that method throughout the project. Do I just create a .java file with a public method and that will give access throughout? Will I need to declare it anywhere (somewhere in the manifest?)?
I'm sure this has been asked, but I am not returning anything useful on my google searches. I am not good enough at googling for Android, yet! Sorry for adding to the duplicates, if I am.
You have a few options. The simplest is a public static method.
public class MyClass {
public static MyReturnType myMethod(MyArgumentType input) {
// my code here
}
}
You will now be able to call this like:
MyClass.myMethod(arg);
Use static methods. As for me, if I want to store just methods in the same place I create a new class and all of the methods are static. For example.
public static int parseInt(String str)
{
try
{
return Integer.parseInt(str);
}
catch (NumberFormatException e)
{
return -1;
}
}
If it's just do anything and doesn't require to save state in the class, this is the best solution.
Here's a sample of a static method.
public class Messages {
public static String mySpecialFinalMessage(){
return "Hello Stackoverflow";
}
}
You no longer need to create an Instance of Messages to call mySpecialFinalMessage() because it is a static. The best practice to call a static method is in this format CLASSNAME.STATICMETHODNAME();
So in our example,
Messages.mySpecialFinalMessage()
Please Note that you calling static methods inside non-static method is legal however, calling non-static methods inside static methods will give you a compile time error.
this is legal
public class MyMessage {
public String getMessage(){
return Messages.mySpecialFinalMessage();
}
}
Take note taht Messages.mySpecialFinalMessage() is that static method. Also, Notice that we did not create an instance of Messages to call mySpecialFinalMessage(), rather we've just called it directly by CLASSNAME.STATICMETHODNAME

Need help to get two classes to assist each other

i'm currently just fooling around with different classes to test how they work together, but im getting an error message in NetBeans that i cant solve. Here's my code:
class first_class.java
public class first_class {
private second_class state;
int test_tal=2;
public void test (int n) {
if (n>2) {
System.out.println("HELLO");
}
else {
System.out.println("GOODBYE");
}
}
public static void main(String[] args) {
state.john();
TestingFunStuff.test(2);
}
}
class second_class
public class second_class {
first_class state;
public int john () {
if (state.test_tal==2) {
return 4;
}
else {
return 5;
}
}
}
Apparently i can't run the method "john" in my main class, because "non static variable state cannot be referenced from a static context" and the method "test" because "non static method test(int) cannot be referenced from a static context".
What does this mean exactly?
Screenshot of the error shown in netbeans: http://imageshack.us/photo/my-images/26/funstufffirstclassnetbe.png/
It means state must be declared as a static member if you're going to use it from a static method, or you need an instance of first_class from which you can access a non-static member. In the latter case, you'll need to provide a getter method (or make it public, but ew).
Also, you don't instantiate an instance of second_class, so after it compiles, you'll get a NullPointerException: static or not, there needs to be an instance to access an instance method.
I might recommend following Java naming conventions, use camelCase instead of under_scores, and start class names with upper-case letters.
The trick here to get rid of the error message is to move the heavy work outside of main. Let's assume that both lines are part of a setup routine.
state.john();
TestingFunStuff.test(2);
We could create a function called setup which contains the two lines.
public void setup() {
state.john();
TestingFunStuff.test(2);
}
Now the main routine can call setup instead, and the error is gone.
public static void main(String[] args) {
setup();
}
However, the other members are correct in that your instantiation needs some cleanup as well. If you are new to objects and getting them to work together might I recommend the Head First Java book. Good first read (note first not reference) and not all that expensive.
Classes can have two types of members by initialization: static and dynamic (default). This controls the time the member is allocated.
Static is allocated at class declaration time, so is always available, cannot be inherited/overridden, etc. Dynamic is allocated at class instantiation time, so you have to new your class if you want to access such members...
It is like BSS vs heap (malloc'd) memory in C, if that helps..

Categories

Resources