I'm new to Java, and I've read over some tutorials on overriding methods, but an example I'm looking at isn't working the way I expect. For example, I have the code:
public class A{
public void show(){
System.out.println("A");
}
public void run(){
show();
}
public static void main( String[] arg ) {
new A().run();
}
}
public class B extends A{
#Override
public void show(){
System.out.println("B");
}
}
When I instantiate and call B.run(), I would expect to see "B" outputted. However, I see "A" instead. What am I doing wrong?
Edit: Yes, the classes are in two separate files. They're shown together for brevity.
Edit: I'm not sure how B is being instantiated, as it's being done by a third-party program using a classloader.
Edit: More info on the third-party program. It starts by calling A.main(), which I didn't initially show (sorry). I'm assuming I need to make "new A().run();" more generic to use the name of the current class. Is that possible?
That code will output B if you:
(new B()).run();
Whatever the problem is, it's not in the code you've quoted.
Updated (after your edit)
If the third-party program is calling A.main(), there's nothing (reasonable) you can do in B that will inject itself into A. As long as A.main is doing new A().run(), it's going to have an instance of A, not an instance of B. There's no "current class name" to use, or if there is (depends on your point of view), it's A, not B.
You'll have to get the third-party program to call B in some way, rather than A, or just modify A directly (e.g., getting rid of B entirely). You do not want to modify A to make it use B; that tightly binds it to a descendant and makes the separation between them largely pointless.
Hope that helps.
I tried, putting your two classes in two files, and it worked nicely, outputting "B". I called :
B b = new B();
b.run();
UPDATED : Also works as (because it is the same runtime instance):
A a = new B();
a.run();
Works for me.
Here's my code for A and B:
package so;
public class A{
public void show(){
System.out.println("A");
}
public void run(){
show();
}
}
class B extends A{
#Override
public void show(){
System.out.println("B");
}
}
Here's my entry point:
package so;
public class EntryPoint {
public static void main(String[] args) {
B b = new B();
b.run();
}
}
It prints out 'B'.
It depends of instantiating. Try this:
A v1 = new A();
A v2 = new B();
B v3 = new A();
B v4 = new B();
v1.run()
v2.run()
v3.run()
v4.run()
I tried your example and my output was B.
How are you instantiating? Here's the exact code I ran.
public class Test {
public static class A {
public void show() {
System.out.println("A");
}
public void run() {
show();
}
}
public static class B extends A {
#Override
public void show() {
System.out.println("B");
}
}
public static void main(String args[]) {
A a = new B();
a.run();
}
}
If your external program instantiates A, you will have A, not B.
But you can try something like this, using some reflection, and pass "com.mypackage.A" or "com.mypackage.B" as arguments to your program.
With this code (exception catch missing), you will be able to print "A" or "B" depending on the string parameter that you pass.
public static void main( String[] arg ) {
String className = arg[0];
Class myClass = Class.forName(className);
Constructor cons = myClass.getConstructor(new Class[0]);
A myObject = (A) cons.newInstance(new Object[0]);
myObject.show();
}
Related
I'm studying for a Java-exam and have a question concerning static and dynamic types.
I've got 4 classes: A, B, C and Main.
public class A {
private void tell(){
System.out.println("AA");
}
}
public class B extends A {
public void tell(){
System.out.println("BB");
}
}
public class C extends B {
}
public class Main{
public static void main(String[] args) {
A c = new C();
c.tell();
}
}
My suggestion was: the output should be "BB", because c has the dynamic type C. Since C doesn't have the method "tell" the method of the upper class B is used, which prints "BB".
The outcome however is an error, because Java looks for "tell" in A. In A it of course can't find it, because there it is declared priavte. But why does it look in A, although only it's static type is A, but it's dynamic type is C?
You are getting an error because at compile time, the compiler does not know the actual instance that will be put in A, so when the compiler sees c.tell() he only looks at the class A which indeed does not have an acessible tell() method.
One way to understand this is with this example:
public class A {
private void tell(){
System.out.println("AA");
}
}
public class B extends A {
public void tell(){
System.out.println("BB");
}
}
public class C extends A {
}
public class Main{
public static void main(String[] args) {
A b = new B();
b.tell();
A c = new C();
c.tell();
}
}
You can see that the first 2 lines would be ok (by your current logic of thinking). B has the method tell() so b should be able to call tell(). But using the exact same assignment with another subclass of C which does not have the tell() method then your logic would fail. A nor C have the tell() method so the program suddenly has a call to a method that does not exist or is not accessible.
My code is similar to this:
class Base{
public void handleObject(A a){
//more code...
System.out.println("A");
}
}
class Sub extends Base{
public void handleObject(B b){
//more code specific to this instance and class B
System.out.println("B");
}
public void handleObject(C c){
//more code specific to this instance and class C
System.out.println("C");
}
}
Where B and C inherit from A.
I then want to call handleObject of Base from this code:
//...
Sub s = new Sub();
A[] obj = {new B(), new B(),new C(), new A()};
for(A o:obj){
s.handleObject(o);
}
//...
And I expect Sub.handleObject(B b) to be called for each object of type B, Sub.handleObject(C c) for type C, and Base.handleObject(A a) to be called for objects of type A.
The real result is it prints "A" three times.
Is it possible to make it work using java's overloading capabilities or must I type check every object myself? If not, what is the best practice to achieve the desired behavior?
This question is very similar to mine but the answers only show why his attempts did not work and did not offer a sufficient solution for me.
I have also tried making it work using Visitor Pattern, but in their example it seems like it is required for the Base class (or at least the interface) to know about Sub, which is something I prefer not to have my project.
I suggest you use polymorphism to your advantage. Instead of trying to figure out how to behave for different classes of objects, let each class provide its own behavior:
class A {
public void handleMyself() {
System.out.println("A");
}
}
class B extends A {
#Override
public void handleMyself() {
System.out.println("B");
}
}
class C extends A {
#Override
public void handleMyself() {
System.out.println("C");
}
}
class Base {
public void handleObject(A a) {
a.handleMyself();
}
}
class Sub extends Base {
public static void main(String... args) {
Sub s = new Sub();
A[] obj = {new B(), new B(), new C(), new A()};
for (A o : obj) {
s.handleObject(o);
}
}
}
I am trying to update a jlabel from another class. I've pasted my code below.
Class A {
public void setNetAmount(String s){
jLabel51.setText(s);
}
public void setDis_percentage(String s){
jLabel53.setText(s);
}
public void setDiscount(String s){
jLabel55.setText(s);
}
public void setAdjustment(String s){
jLabel57.setText(s);
}
}
Class B{
public void SetData(){
new A.setNetAmount(""+netAmount);
new A.setDis_percentage(""+dis_percentage);
new A.setDiscount(""+discount);
new A.setAdjustment(""+adjustment);
}
}
I am calling the SetData() method in Class A.
public void getData(){
B b = new b();
b.setData();
}
Is there anything wrong with my code ? It is not working at all. Is there any issue of EDT? Please help.
You can't keep invoking "new A". This creates a new instance of class A.
Not really sure why you have a class B to invoke a few methods from class A, but if you use this approach then you would need to pass a reference of class A the your class B method.
Something like:
public class B
{
public void setData(A a)
{
a.setAmount(...);
a.setPercentage(...);
...
}
}
Then when you invoke the method in your class A you would use:
B b = new B();
b.setData(this);
Although this is a really strange design.
Say I have Class A and Class B. Class B extends Class A. Class A has one method.
public class notimportant
{
public void one()
{
}
}
public class A extends notimportant
{
public void one()
{
//assume there is a super class making this call legal which doesnt do anything
super.one();
System.out.println("blah");
}
}
public class B extends A
{
}
A var1 = new B();
if I call 'var1.one();' will the output end up being:
"blah"
"blah"
because it creates a local copy of 'one()' in Class B and then reads that which calls 'super()' which leads it up to method 'one()' in Class A OR does it just print
"blah"
because it knows to look directly at Class A
EDIT: Hope that is a lot more clear now.
It will follow the way you have it currently written:
-> New object of class B
-> Call method One on this object
-> First line calls supermethod, proceed to execute it
-> Second line prints out after that
Your code doesn't compile at all though, you might want to clear that up. What's keeping you from testing this yourself?
Here's the new situation as you described it. Everything still works as expected, you just add a layer.
public class C {
public void test() {
System.out.println("Inside C");
}
}
public class B extends C {
public void test() {
super.test();
System.out.println("Inside B");
}
}
public class A extends B {
public static void main(String[] args) {
A obj = new A();
obj.test();
}
}
Output:
Inside C
Inside B
super means your superclass – it's resolved at compile-time.
It does not mean the immediate parent class of whatever the runtime type of this is.
In the code below, myString is always initialized to null. I have to manually initialize in an init() or similar. As far as I can tell it is related to superclass/subclass but I don't understand the exact mechanism
public class A extends B {
private String myString = "test";
public static void main(String[] args) {
new A();
}
public A() {
super();
}
public void c() {
System.out.println(myString);
}
}
public class B {
public B() {
c();
}
public void c() {
}
}
The issue with your code is, that myString is initialized at the begin of the constructor of class A but right after the super constructor (i.e. class B). Since you access the variable before from the constructor of class B (indirectly via call to overriden methode c) your get this behaviour.
As a rule of thumb: if you want to avoid unexpected behavior do not call overriden methods before the constructor has been executed.
Add a call to c(); overidden method right after the object has been fully created and call to superclass constructor is done.
Change your code to this ..
public class A extends B {
private String myString = "test";
public static void main(String[] args) {
new A();
}
public A() {
super();
c(); // Include the call to c(); here ...
}
public void c() {
System.out.println(myString);
}
}
public class B {
public B() {
}
public void c() {
}
}
// Output : test
Thinking in Java Second Edition by Bruce Eckel, Behavior of polymorphic methods
inside constructors (p. 337-339).