For example, I have a class called Foo inside Foo.java which will use a class called Bar inside ../Bar.java. Is there any way to make that work when I do javac Foo.java?
Add your class to classpath..
javac -cp "path to your Bar.class" Foo.java
You will need to import that class in your Foo.java also.. Better use a package, and give the classpath till the directory containing your package..That way you will be able to give different namespaces to your classes..
So, if your package is: - pkg1.pkg2.Barand you have saved your .java to a directory named Demo, then your classpath should contain path till Demo.. And your classes will actually be under two more directory pkg1/pkg2/Bar.class inside Demo directory..
Demo+
|
+-- B.java (`Under package pkg1.pkg2)
|
+--pkg1+
| |
| +--pkg2+
| |
| +-- B.class
|
+-- A.java (`Under no package`) - Add - import pkg1.pkg2.B
|
+-- A.class (javac -cp . A.java) - Will search the package pkg1.pkg2 in current directory
Even though . is not needed there, you can replace it with any path, if your B.class is somewhere else..
Assuming these are both your classes and belong to the same module, you should be using packages and both classes should exist in the same package hierarchy. Then it would work automatically.
Packages would be something like com.company.application.module.Bar and com.company.application.module.subcomponent.Foo, for example. See more discussion on correct package naming:
Oracle.com: naming packages
wikipedia: package naming conventions
You can also do javac -sourcepath path/to/src/solution/java;path/to/src/test/java to point to several locations explicitly (note that -classpath will also work, see this discussion about the differences).
If we're talking about separate components that don't exist in the same module, you'd just use classpath to make the code aware of both (or preferrably some dependency mechanism like Maven that works out the stuff under the hood).
Your classes have packages, which are mirrored in the directory structure. E.g. com/company/pk/Foo and com/company/Bar - then you can reference them using the import statement. If your classes are in different directories but don't declare a package, then you are doing it wrong.
Read about packages
Related
I was wondering if there is any way that allow us to import packages in a class using a relative path.
To set an analogy, in html you can use a relative path to set an hyperlink.
For example, given this Files Structure:
Folder: "A"
|
|____________ Folder: "B"
| |
| |
| |
| |_________ File html: "Link.html"
|
|
|
|________ File html: "Index.html"
So, in the file "Link.html" I can set this Hyperlink:
<!DOCTYPE html>
<html>
<head>
<title>Link</title>
</head>
<body>
<main>
<h1>You are in the file "Link"</h1>
<!--This would be the hyperlink-->
Go to Index
</main>
</body>
</html>
My question is:
Could I create a package for example in folder "B" and import the class from that folder "B" in a java file which would be in folder "A"?
I mean without using "classpath" (I don't say without using "sourcepath" too, because I'm not sure about how it works).
Folder: "A"
|
|____________ Folder: "B"
| |
| |
| |
| |_________ File Java: "Example.java"
|
|
|
|________ File Java: "Main.Java"
Moreover, could I set an absolute path in a java file directly to import a package without having to tell the compiler, manually, where the packages are through classpath? (Like in html?)
I mean something like this example but when importing a package in java:
Go to Index
Thanks in advance ;)
I was wondering if there is any way that allow us to import packages in a class using a relative path.
No. Java doesn't support that. Package names are fully qualified when you define them and fully qualified when you use them.
My question is: Could I create a package for example in folder "B" and import the class from that folder "B" in a java file which would be in folder "A"?
For the OpenJDK Java tool chain, and anything else that uses the same class resolution mechanisms1, the folder name structure must map to the package structure. So assuming that the folder above A is the root of your (source or binary) class folder tree, then your Main.java file needs a package declaration
package A;
and your Example.java file needs a package declaration:
package A.B;
(Note that case is significant, and package names A and B are a Java style violation.)
Class Example can import Main and vice versa, but they must use the fully qualified package names to do that; i.e.
import A.Main;
import A.B.Example;
Q: Can you trick the compiler / runtime by having a class / package naming scheme that doesn't correspond to the file / folder structure?
A: No. Either the Java compiler or runtime will fail to find classes or it will detect that there is a mismatch a class's fully qualified and the place where it was found. In both cases you will get an error.
Q: Can you import by file pathname?
A: No. The Java language doesn't permit this. Just ... no.
I mean without using "classpath" (I don't say without using "sourcepath" too, because I'm not sure about how it works).
That doesn't make sense. You cannot "not use" a classpath. If there is no classpath, the Java tools cannot find your code. There is always a classpath ... even if it is just the current directory; i.e. ".".
1 - As far as I am aware, this covers all current practical Java implementations. However, it is technically possible (and permitted by the Java Language Specification) for a Java implementation to use some other mechanism for organizing and locating source code or binary code "entities".
For your first question: Java packages are used to do just that, but the CLASSPATH is still in use. The default class loader will look under the CLASSPATH for classes and expect them to be located based on their package names. (There are other class loaders that have different behaviors, but mostly you will use the default one.)
For your second question: No you cannot. As explained above, the default class loader will look under the CLASSPATH for any class you import, and will try to locate based on the package name of classes. (Again, assuming you use the default class loader.)
Java packages are the standard way of structuring your code, and for most cases this structure is also replicated on the file system (for both source and class files).
I'm answering myself because I don't want to confused anyone else.
As far as I've understood:
The "Relative path" I was looking for were in fact java packages.
As #Fererico-klez-Culloca said, having this example:
Folder: "A"
|
|____________ Folder: "B"
| |
| |
| |
| |_________ File Java: "Example.java"
|
|
|
|________ File Java: "Main.Java"
Main just has to import A.B.Example.
However, there are 2 things that must be considered:
Main has to have "package A", Example.java has to have "package A.B".
Supposing I'm using visual studio, in order to compile it I can't do it opening the folder "a" directly as it will give me an error. As I still have to understand more in depth how this works, I'll quote another person words:
"In Visual Studio, you need the "source folder" to be the folder above a, not a itself, because package names are resolved relative to the source folder. "
A way to resolve this would be creating another folder, so the files schema could be something like this:
Folder: "Project_Folder"
|
|
Folder: "A"
|
|____________ Folder: "B"
| |
| |
| |
| |_________ File Java: "Example.java"
|
|
|
|________ File Java: "Main.Java"
Having that, I have to open the folder (project) in "Project_Folder", so that the compiler can find the folder "a", and identify it as a package.
Although "absolute path" doesn't really exist in java, It's true that "classpath" can act similar to it, nevertheless classpath and "absolute path" (of html) are not exactly the same.
I want to write a code like this
package mypackage;
public class A extends B {
}
But all that I have is the B.class file which is compiled from a single B.java file with no package specified.
Could anyone help me out?
Thanks!
I've tried putting B.class in my ./src and A.java in ./src/mypackage and run javac -cp src ./src/package/A.java but it wouldn't compile. It wouldn't compile neither if I put B.class in the same folder as A.java
You can't. By your description, class B is in the default (unnamed) package. The Java language rules do not allow classes outside the default package to refer to classes in the default package.
The only way you can use this class is to put A in the default package as well. That is, move it one directory up, and remove the package statement.
Alternatively, you need to have the sources of class B (or decompile it), move it into a package and add a package statement, and recompile.
I have a project that has some android specific code and desktop specific code. Since Java does not have something like #ifdef I place the os specific code in its own directory. something like this
project
+-- common
| +-- src
| +-- com
| +-- example
| +-- common1.java
| +-- common2.java
+-- desktop
| +-- src
| +-- com
| +-- example
| +-- platform.java
+-- android
| +-- src
| +-- com
| +-- example
| +-- platform.java
Depending on which platform the code is being built for the code from desktop or android is included in the build.
however I am having difficulty building this with SCons
example snippet from SCons build script
#target contains the platform we are building on
if target in ['windows', 'linux']:
java_class_out = env.Java(target='classes', source=['desktop/src', 'common/src'])
jar_out = env.Jar(target='myOutput.jar', source=java_class_out);
when run this will look something like the following:
javac -d classes -sourcepath common/src common/src/com/example/common1.java common/src/com/example/common2.java
javac -d classes -sourcepath desktop/src desktop/src/com/example/platform.java
desktop/src/com/example/platform.java:42: error: cannot find symbol
The cannot find symbol error is repeated for every symbol that is in platform that came from common1.java or common2.java
I tried to pass in an array of all of the java files:
Updated snippet from SCons build script.
#target contains the platform we are building on
if target in ['windows', 'linux']:
java_files = ['desktop/src/com/example/platform.java',
'common/src/com/example/common1.java',
'common/src/com/example/common2.java']
java_class_out = env.Java(target='classes', source=java_files)
jar_out = env.Jar(target='myOutput.jar', source=java_class_out);
this results in output similar to this:
javac -d classes -sourcepath common/src/com/example common/src/com/example/common1.java
javac -d classes -sourcepath common/src/com/example common/src/com/example/common2.java
javac -d classes -sourcepath desktop/src desktop/src/com/example/platform.java
desktop/src/com/example/platform.java:42: error: cannot find symbol
What I want SCons to do is output something similar to this:
javac -d classes -sourcepath common/src -sourcepath desktop/src common/src/com/example/common1.java common/src/com/example/common2.java desktop/src/com/example/platform.java
There was a thread on the Scons-users mailing list asking almost this exact question but no solution was given.
Full email chain that I could find with google:
https://pairlist4.pair.net/pipermail/scons-users/2016-February/004609.html
Anyone know how to get Scons to do what I need? Unfortunately I am stuck with SCons for building.
SCons is clever enough to add the source folder for your call to the Java() method as default parameter to the -sourcepath option. But if you simply say
env.Java(target='classes', source=['desktop/src', 'common/src'])
this will internally result in two separate calls, having the effect of:
env.Java(target='classes', source=['desktop/src'])
env.Java(target='classes', source=['common/src'])
. That's why you always just get one path, but not the other with your approach.
Instead, you have to use the provided JAVASOURCEPATH variable (please search our User Guide, there is only one occurrence) to specify the list of folders that should be searched for class or interface definitions.
Either
env.Append(JAVASOURCEPATH=['desktop/src', 'common/src'])
env.Java(target='classes', source=['desktop/src', 'common/src'])
or
env.Java('classes', 'desktop/src', JAVASOURCEPATH=['common/src'])
env.Java('classes', 'common/src', JAVASOURCEPATH=['desktop/src'])
should do the trick. Note, how I omitted the source/target specifiers in the last code snippet for brevity, but explicitly naming the parameters should work too.
I'm trying to figure out how javac works with regard to stuff like sourcepath, classpath and prebuilt classes etc. I'm trying to read the documentation, but can't really make sense of it.
I've tried to think of some sample cases below.
If I'm compiling a single file onlyfile.java which has no dependencies, which has 2 classes A and B , and class A uses class B , does class B need to be defined/declared before A ? Or is javac smart and does multiple passes or something like that ?
root.java uses another class in a file file2.java located in the same folder. If I execute javac root.java , how does javac know to search the folder for the class file and if not found , for source file instead ?
How does the above work if the file2 is located in a subdirectory ?
EDIT:
I read somewhere that import is just a way to cut down on typing rather than "loading" anything like in python.
Suppose that I'm building only 1 java file which uses multiple other classes, and that these class files already exist. Without import, the a.b.c.d part of the class object already tells me where to search for the class file, then why a cp option ?
1) If you compile class A which uses class B then class B will be compelled as well. If you compile class B (which is used inside A, but A is not used inside B), class A will not be compelled. Find more details end examples here.
2) javac searches inside source-path and class-path. If you run javac without arguments like javac A.java it sets classpath and sourcepath to current directory. If requested class is not found neither in classpath nor in sourcepath you'll have compilation error.
3) Java has strict rules for project structure. You can't simply place source file to another folder without updating file content.
Every folder in the project should have folder hierarchy with respect of package declaration.
Definition: A package is a grouping of related types providing access protection and name space management.
for instance if you have class A.java with package declaration like this
package com.mycompany;
The corresponding folder structure should look like this:
com/mycompany/A.java
If you follow this rules compiler will be able to resolve dependencies just like I explained in #1. Find more information here.
For first two options try with javac *.java
Duplicate of Compiling Multiple Classes (Console) in Java
Going by the Java Tutorial for package naming convention if I were to use the following approach:
org.example.hyphenated_name.user
org.example.hyphenated_name.product
How would this translate to actually creating this package structure. Would I create a separate package for org then within org would i create example and so on or would it just be 2 packages org.example.hyphenated_name.user and org.example.hyphenated_name.product
Basically what I'm wondering is if the . is just used for naming separation or if it's used to mean physically creating a new package each time.
This is how it looks physically on a disk drive:
$ mkdir -p org/example/hyphenated/name/user
$ mkdir -p org/example/hyphenated/name/product
$ tree org
org
└── example
└── hyphenated
└── name
├── product
└── user
5 directories, 0 files
So actually, you have a structure of packages:
org
org.example
org.example.hyphenated
org.example.hyphenated.name
org.example.hyphenated.name.product
org.example.hyphenated.name.user
By creating such a structure, you can now use each package for a different action. Product-specific action classes in org.example.hyphenated.name.product and user-specific in org.example.hyphenated.name.user package. This way you can as well put classes that use both of these packages in e.g. org.example.hyphenated package. This way you create a well-build application structure that is easier for other people (and for you in 2-3 months) to read.
EDIT:
Normally you won't need to care about creating folders for packages, because your IDE should take care of this instead of you.
A package isn't a "thing" that you have to create (except that you normally have to create the directory hierarchy for storing the source files). You pretty much just say that your class belongs to some package, and the compiler says "OK, whatever you want". There's no built-in relationship between package_a.package_b and package_a.package_b.package_c that has any effect on language semantics. (What I mean here is that if you have a class in package_a.package_b.package.c, then within that class there is nothing special about classes in package_a.package_b as opposed to, say, package_z.package_y. In both cases, it's just "some other package".)