How do I do forward declarations in Java?
I have two classes, each needs to call a method in the other and they both reside within different namespaces. For example...
package one;
class A {
public void foo() {
B b = new B();
b.bah();
}
}
and
package two;
class B {
public void bah() {
A a = new A();
a.foo();
}
}
UPDATE
In Eclipse when this code is encountered a compile time error would be thrown up "A cycle was detected in the build path...".
Just import them. Java is a lot cleverer than C++ about these things.
In Eclipse when this code is encountered a compile time error would be thrown up "A cycle was detected in the build path...".
I think that Eclipse is complaining because you have a circular dependency between classes in different Eclipse projects in your workspace. Eclipse wants to be able to build projects in a linear sequence.
If you put the mutually dependent classes into the same project, Eclipse would be happy.
Well, you import the classes:
package one;
import two.B;
class A {
public void foo() {
new B().bah();
}
}
or use their full name:
package one;
class A {
public void foo() {
new two.B().bah();
}
}
But, needless to say, that will cause an exception to be thrown (at least, in the snippet you posted...).
Given the comments here (ie you don't need to do explicit forward declarations as the compiler can cope) I have downgraded the Eclipse error to a warning and will have to just ignore it.
To do this go to...
Window > Preferences > Java > Compiler > Building > Build path problems > Circular dependences
Related
Consider the following scenario:
Let say I have a class A in "src" folder of my project.
class A {
void foo() {
B b = new B();
}
}
Class B is defined in another jar which is included as a dependency in build.gradle
class B extends C {
}
Now, Class C is defined in another jar which will be provided on runtime and not on compile time. Gradle is able to compile Class A without error.
But, when I import Class c in Class A then it gives "class not found".
import other.C; // this line gives error
class A {
void foo() {
B b = new B();
}
}
Is this the desired behavior of Java compiler to ignore the Class C if it not imported directly?
Also, what happened if use a function in class A using object of B which is in Class C but not overridden in class B.
The exact answer to your question depends on the Java compiler version and whether or not it requires access to C for doing its job.
All in all, I would say that such a setup is fragile and you should not do it. If your library that defines A requires B which effectively makes use of C in its public API as is the case for extends then C should be made visible to your library.
First of all we need to understand how java compilers work.
Whatever you reference by name or as a 'token' in your code, should be accessible to compiler during compilation phase.
The classes that you load using Class.forload or getClass method are not required to be available in the classpath.
What you are essentially referring by compiletime and runtime is about packaging.
What you say that a particular dependency say Class C will be provided at runtime, its an instruction to bundle tasks to ignore that dependency while building the jar. So if you compile and deploy your application as jar, class C will not be present in it. At the same time, the jar containing class B will be included in your deployment package.
If you provide exact gradle file, I might be able to answer more precise.
I have googled and searched the best I could, but I still could not find an solution. Maybe my search queries was not correct or details.
I do know there are a number of API changes from java 8 to 10. The jdk structure for 8 to 10 has also a significant changes.
Problem:
I have the following dependencies:
Project A --> Project B --> Project C
Some class in project A will call classes in Project B and B will call C. In Java 8 there were no issues.
After I upgrade to Java 10, a NoClassDefFoundError exception occurs.
I found two ways to overcome the issue
Project A now also depends on Project C
In the Java Build Path tab --> Order and Export tab, checked the Project C checkbox.
Question
Is there a better way to resolve my problem instead of using the solutions I found? Because my project codes are huge and it will take a lot of time to do so.
I would also like to know the underlying cause of the problem if possible.
Code:
ClassA.java (Project A):
package pkg;
public class ClassA {
public ClassA() {
new ClassB();
}
public static void main(String[] args) {
new ClassA();
}
}
ClassB.java (Project B)
package pkg;
public class ClassB {
public ClassB() {
callClassC();
}
public void callClassC() {
ClassC classC = new ClassC();
String info = classC.getInfo();
System.out.println(info);
}
}
ClassC.java (Project C)
package pkg;
public class ClassC {
public String getInfo() {
return "Class c info";
}
}
I also exported a eclipse workspace for my issue. I created this workspace using an older version of eclipse and java.
I can reproduce this. The code compiles, but you get an error when executing.
This is an eclipse bug.
Please report it at https://bugs.eclipse.org.
A possible workaround: Edit the run configuration, go to the Dependencies tab, use Add variable string with the value ${project_classpath}
interface A
{
public void f();
public void g();
}
class B implements A
{
public void f()
{
System.out.println("B.f()");
}
}
public class Main
{
public static void main(String[] args)
{
B tmp = new B();
tmp.f();
System.out.println("B.f()");
}
}
I don't implement all the method in the interface A in B
and it has a error that
The type B must implement the inherited abstract method A.g()
but why it can get the output that
B.f()
B.f()
Eclipse allows you to run code with compile-time errors - after giving you a warning and offering you the option to back out (which you should normally take).
If you try to call tmp.g() you'll get an exception indicating a compile-time failure.
Occasionally it can be useful to run code which doesn't fully compile - particularly if the compile-time failure is unrelated to the code you actually wish to run, e.g. when unit testing - but I would be very careful about how you use this feature.
Eclipse can "patch" around certain classes of compile errors, and run a program even if errors exist. Normally, you get a dialog box that says the following:
Errors exist in required project(s):
(project name)
Proceed with launch?
[X] Always launch without asking
If you select Proceed, or if you have disabled the dialog, Eclipse will proceed to fix the compile errors if possible. If you try to run code impacted by the compile error, you'll get a runtime exception.
In this case, Eclipse adds a dummy B.g() method containing just the following:
throw new java.lang.Error("Unresolved compilation problem: \n"
"The type B must implement the inherited abstract method A.g()");
By inserting this dummy method, the code will compile properly and it will run. If you never call B.g, then you'll never see this error.
Guys, can anyone explain the following scenario:
1) Web application has module1.jar in its lib directory. There is a class A in that module:
package module1;
import module2.B;
public interface IA {
void methodOk() {}
void methodWithB(B param) {}
}
package module1;
import module2.B;
public class A implements IA {
public A() {}
//...
void methodWithB(B param) {
//do job on B
}
}
2) module2.jar is absent - it is not in the classpath.
3) Application is able to create objects of class A though it's missing the dependency. In application a method A.methodOk() is called.
Would be cool if you could give a reference to any spec on this.
Thanks a lot.
Since the code is already compiled, it will not throw an error until you directly use class B. From the looks of your code, you don't actually use an instance of B for anything.
If B is not used by A anywhere, then the resulting bytecode will have no reference to module2.B, therefore it gets compiled away. No dependency exists, except at compilation in this case.
If the question is unclear and B is used in A somewhere, then I'd be interested in seeing more code to try to determine what's going on.
Look at it from the perspective of the classloader. If you never have to load the class, you don't care if the bytecode for that class is missing.
Your question is really, "What triggers classloading?"
Two reasons I can think of off the top of my head are:
- Construction
- Static access
I have three .java files and I need to get them to work together. I think that I need to add all the classes to a main method but I am not sure if this is correct and if I just add the name of the class and the format.
I figured it out, the three files had a package listed at the top of each. I created a new Java project in Eclipse and then a source folder and in the source folder I created a package with the name that they all referenced. Now it runs. Thanks for all of you help for the Eclipse/Java beginner.
You are right: what you think is not right :P
Java can find the classes that you need, you can just use them straight away. I get the feeling that you come from a C/C++ background (like me) and hence think that you will need to "include" the other classes.
java uses the concept of namespaces and classpaths to find classes. Google around for it.
A little example of how variety of classes can be used together:
// A.java
public class A {
public void sayIt() { sysout("Said it by A!"); }
}
// B.java
public class B {
public void doIt() { sysout("Done it by B!"); }
}
// MainClass.java
public class MainClass {
public static void main(String[] args) {
A aObj = new A();
B bObj = new B();
aObj.sayIt();
bObj.doIt();
}
}
Note that there are no includes/imports here because all of the classes are in the same namespace. If they were not, then you'd need to import them. I will not add a contrived example for that coz its too much to type, but should google for it. Info should be easy enough to find.
Cheers,
jrh
If they are in the same package you do not need to do anything, as they are automatically imported for you, but otherwise you'll need to add import statements before your class declaration.
Once this is done, you can reference static members directly ie ClassB.staticMethod(); or instantiate the class ie ClassB classb = new ClassB();
But honestly, if you are this confused, you need to spend some more time doing tuturials.
http://eclipsetutorial.sourceforge.net/totalbeginner.html
http://download.oracle.com/javase/tutorial/getStarted/cupojava/index.html
http://www.freejavaguide.com/corejava.htm
I am not sure what you mean by "adding classes to a main method". If you want to make use of several classes inside your Java program, just import the needed classes/packages at the beginning and create an instance of each class as you go along.
I learned this from a beginner program called Jeroo
Basically if I want to create a new "Jeroo", I would write the following on my Main method:
Jeroo Bob = new Jeroo();
{ methods... }
So basically:
[class] [customnameofclass] = new [class]