What will happen if i create my own String class in java? - java

When i create my own String class .If there is another class in same package , main(String[] args) seems to pick my String class instead of the one present in rt.jar. My question is , why String class from rt.jar is not picked by Bootstrap Class loader in this case. My understanding is a class loading request that comes to Application loader will be delegated to bootstrap class loader.

Because the String in your local package takes precedence; you can explicitly use java.lang.String or name your class String something else1.
public static void main(java.lang.String[] args)
To expand on the above, at compile time the compiler resolves class names to their fully qualified form (at the byte-code level, there aren't any imports). Further, Java includes a String intern pool that is initialized before your class is loaded (in order for that to function, java.lang.String has to be loaded before any user classes).
1Which is really a better idea, shadowing classes from java.lang is asking for a maintenance nightmare.

Why is the String class from rt.jar not picked by the bootstrap class loader in this case. My understanding is a class loading request that comes to Application loader will be delegated to bootstrap class loader.
The name resolution actually happens at compile time. The compiler decides what String means in the context of the source code file that is using it and then uses the full name for the resolved class (e.g. java.lang.String or your.pkg.String) in the class file. At runtime, Java class loaders always load classes using a full class name.

Related

What is Difference between ClassNotFoundException vs NoClassDefFoundError vs Could not find or load main class XYZ?

I explored multiple sites but could not actually understand difference between them.I would like to know the exact difference between three.
A NoClassDefFoundError is thrown,if a classfile references a class, that couldn't be found at runtime, but was available at compiletime.
(Source: https://docs.oracle.com/en/java/javase/14/docs/api/java.base/java/lang/NoClassDefFoundError.html)
A ClassNotFoundException is thrown when an application tries to load in a class through its string name using:
The forName method in class Class.
The findSystemClass method in class ClassLoader .
The loadClass method in class ClassLoader.
(Source: https://docs.oracle.com/en/java/javase/14/docs/api/java.base/java/lang/ClassNotFoundException.html)
The error message Couldn't find or load main class XYZ, means a lot of things:
You specified the wrong class (Typo)
The class in the classfile specified is (not) in a package. (Like java c, but the class is in the package a.b, so the command should be java a.b.c)
More information/causes: https://stackoverflow.com/a/18093929/13912132
NoClassDefFoundError - is a run-time error, thrown when the Definition of the class (which is .class file) cannot be found at run-time.
Imagine you've compiled class A.java alongside other files of your project; however, later on, you've removed compiled A.class file. So, compilation went fine, but actual bytecode of the class definition is absent, as A.class has been removed.
ClassNotFoundException - is a checked exception, thrown when your application tries to load the class through its String name, but the class isn't available on class-path.
An example can be Class.forName("com.mysql.jdbc.driver"); method call in your code, when, however, you don't have com.mysql.jdbc.driver available in your project.
Couldn't find or load main class XYZ - is an error, indicating, that the class you instruct JVM to run, doesn't contain the must have entry-point public static void main(String[] args) method, and reasons for this can be different, mainly one from this list:
you don't provide a correct Fully Qualified Name of your main class;
main method is not defined with the correct signature;
you messed up the packaging / you don't run the program with super.sub.grandchild.MainClass name;
you have .class postfix after your classname, which you should remove.
Both ClassNotFoundException and NoClassDefFoundError are caused when the JVM is not able to load a particular file, but their cause differs.
Java runtime throws ClassNotFoundException while trying to load a class at runtime only and the name was provided during runtime. In the case of NoClassDefFoundError, the class was present at compile-time, but Java runtime could not find it in Java classpath during runtime.
Couldn't find or load main class error message can be caused by various reasons, it can also be caused by ClassNotFoundException or NoClassDefFoundError.
Error: Could not find or load main class ClassName.class
Caused by: java.lang.ClassNotFoundException: ClassName.class
NoClassDefFoundError
This occurs when the JVM or a ClassLoader tries to load a class (as part of a normal method call or as part of creating a new instance using the new expression) but it can not be found while it existed when the currently executing class was compiled.
ClassNotFoundException
As mentioned in the documentation, it is thrown when an application tries to load a class through its string name using:
The forName method in class Class.
The findSystemClass method in class ClassLoader.
The loadClass method in class ClassLoader.
It means that it is unknown to JVM whether the class (which is to be loaded) existed when the currently executing class was compiled.

how can I know the current classLoader in java

I am learning the process of loading java class and encounter some confusion.
I know when loading a java class, current classLoader wont load the java class directly and it will delegate to its parent classLoader(a recursive process) until it parent cant load this class.
The question is that :what is the current classLoader? Bootstrap? Extension? App?
how to get the current classLoader?.
and I know there is an API:
xxx.Class.getClassLoader();
but I am not sure whether the return value is currentClassLoader. I think it should be the classLoader which load this java class in reality.
To describe my question more detail I will give an example.
I get the follow content in a blog.
ThreadContextClassLoader is used to deal with java SPI, Interface is defined in java core lib and loaded by Bootstrap ClassLoader and third party implement these interface then the jar are loaded by AppClassLoader
Solution: traditional classLoader cant deal with this case,because it cant discovery the third party jar when we use the third party implement in core lib.
most of the above that I can understand but the solution make me confusion:
for example, the Interface CoreA and class CoreB are in java core lib and should be loaded by Bootstrap ClassLoader and the AImpl is a implement of A by third party and should be loaded by AppClass loader.
the code segment as below:
public Interface CoreA{
void add();
}
public Interface AImpl implements CoreA{
void add(){};
}
public class B{
public void demo(){
a = new AImpl();
}
}
then if we reference B in main method, then we will load B because the class loader of B is Bootstrap then about AImpl the current Loader is Bootstrap so it cant be found?
I dont know whether it is as what I guess?
Any advice will be appreciated.
Generally speaking you are right, it can't be found. Let me show you the following example. Let's say we have 3 classes: A, B and Main like these:
public class A {
public String a() {
return "a";
}
}
public class B {
public String b() {
return new A().a();
}
}
public class Main {
public static void main(String... args) {
System.out.println(new B().b());
}
}
And we package these classes into correspondent jars: a.jar, b.jar and place Main.class into the working directory. After that let's test the following scenarios:
1) Everything (A.class, B.class, Main.class) is loaded by system classloader and works fine:
$ java -cp .:a.jar:b.jar Main
a
2) B.class is loaded by system classloader and A.class is loaded by bootstrap classloader and everything still works fine because system classloader delegates loading to bootstrap classloader (just because bootstrap classloader can load it):
$ java -Xbootclasspath/a:a.jar -cp .:b.jar Main
a
3) A.class is loaded by system classloader and B.class is loaded by bootstrap classloader (your case). In this scenario during loading of B.class current classloader is bootstrap classloader, but it can't found B.class and fails:
$ java -Xbootclasspath/a:b.jar -cp .:a.jar Main
Exception in thread "main" java.lang.NoClassDefFoundError: A
at B.b(B.java:4)
at Main.main(Main.java:4)
Lets take a look at the last example more carefully. What's happening here:
Try to find class with public static main(String[] args) method
1.1. system classloader hasn't loaded it yet so delegates to extension classloader
1.2. extension classloader hasn't loaded it yet so delegates to bootstrap classloader
1.3. bootstrap classloader hasn't loaded it yet and tries to load, it can't load it and returns control to extension classloader
1.4. extension classloader tries to load, it can't load it and returns control to system classloader
1.5. system classloader loads Main.class
Main.class is processed and we try to load B.class with current classloader system classloader
2.1. system classloader hasn't loaded it yet so delegates to extension classloader
2.2. extension classloader hasn't loaded it yet so delegates to bootstrap classloader
2.3. bootstrap classloader hasn't loaded it yet and loads B.class
B.class is processed and and we try to load A.class with current classloader bootstrap classloader
3.1. bootstrap classloader hasn't loaded it yet and tries to load and
fails
I hope it will help you.
When a class A attempts to load another class B, the ClassLoader that loaded A is the current ClassLoader. The word current vaguely refers to the execution context - e.g. how do you end up in the method that triggers the current class loading call.
There is no method - say getCurrentClassLoader - that simply gives the current ClassLoader, but there are api methods that internally use the concept of current ClassLoader. For example, Class.forName(String className)
If you check how that method is implemented, it tells you the meaning of "current class loader":
public static Class<?> forName(String className) throws ClassNotFoundException {
Class<?> caller = Reflection.getCallerClass();
return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
}
If you can get hold of a Class instance, you can always ask for the loader behind it by calling Class::getClassLoader() method. That will be your current class loader. The tricky bit, however, is to decide if the loader is bootstrap, or extension, or system class loader. The reason of the trickiness is that it is implementation specific, and you can always implement your own class loading mechanism.
The example given by #dmitrievanthony is an example of how things can become really complicated. It is a similar situation faced by JNDI, and the reason why the hack Thread.getContextClassLoader() was introduced. More about it here
Quote the most relevant piece from the article:
... By definition, a current classloader loads and defines the class to which your current method belongs. This classloader is implied when dynamic links between classes resolve at runtime, and when you use the one-argument version of Class.forName(), Class.getResource(), and similar methods. It is also used by syntactic constructs like X.class class literals ...
the 'current classloader' is the real classloader(load this class in reality) of class that refer it.
e.g.
if the classLoader of class A is ext classloader and class A refer class B C D. Then the 'current classloader' of B C D is ext classLoader. And of course the 'current classLoader' of main class is System classLoader.

Difference in functionality between instance created by classloader and new keyword

I am little bit confused in class loading and initializing concept
1: Class.forName("test.Employee").newInstance();
2: ClassLoader.getSystemClassLoader().loadClass("test.Employee").newInstance();
3: new test.Employee();
Every line of above written code is creating an instance of Employee class but I don't understand what is the difference in all three methods.
The core differences between the three approaches come down to how the classes are located at runtime and what you can do with them.
For example...
Class.forName("test.Employee").newInstance();
Will use the current class's ClassLoader to search the class named Employee in the test package. This would allow you to discover classes that might not be available at compile time and which are loaded dynamically into the same class loader context. This will also search it's parent class loaders if the class is not found within the current context...
ClassLoader.getSystemClassLoader().loadClass("test.Employee").newInstance();
This will use the "system" ClassLoader, this typically the one that launched the main application.
Using either of these two methods is a great way to generate dynamic applications where the actual implementation of a Class is not known at compile type. The problem here is it can affect visibility and restrict what you can do with the loaded classes.
For example, while you may have loaded the test.Employee class and created an instance of it, unless you have a reference to test.Employee at compile time, you want be able to cast it. This is typically where interfaces come in very handy.
Equally, you could create your own ClassLoader instance and load classes or jars at runtime to provide, for example, plugins, factories or managers where the implementation is unknown at compile time. The functionality for these would, typically, be described through the use of interfaces.
Examples would include java.awt.Toolkit and JDBC java.sql.Driver
At the end of the day, the ClassLoader mechanism is providing a means by which a class file can be loaded and instantiated into the current JVM. The new keyword does a similar job, but the results are pre-determined at compile time
ClassLoaders are a very powerful feature and provide a lot of functionality, but can also be down right confusion, especially the way that they chain together
You might find...
The basics of Java class loaders
How ClassLoader Works in Java
of some help
You cannot create a instance of an Object unless class is loaded into the memory. In all three cases class is loaded and then instance is created.
class is loaded by Class.forName("test.Employee")
class is loaded by ClassLoader.getSystemClassLoader().loadClass("test.Employee")
class is loaded automatically as Employee class is referenced for 1st time.
Just to illustrate it with an example and complete the other answers:
public class ClassLoaderTest {
public ClassLoaderTest() throws InstantiationException, IllegalAccessException, ClassNotFoundException {
System.out.println("Current CL: "+getClass().getClassLoader());
System.out.println("Parent CL: "+getClass().getClassLoader().getParent());
// ClassTest class is defined in the current CL so I can dynamically create an instance
// from the current CL and assign it (forName uses the current CL)
ClassTest c1 = (ClassTest)Class.forName("ClassTest").newInstance();
System.out.println("CL using forName: "+c1.getClass().getClassLoader());
// the new keyword creates an instance using the current CL but doesn't have the
// advantages of creating instances dynamically
ClassTest c2 = (ClassTest) new ClassTest();
System.out.println("CL using new: "+c2.getClass().getClassLoader());
// Here we are indicating to use the system CL that in this case is the parent of the current CL
Object c3 = ClassLoader.getSystemClassLoader().loadClass("ClassTest").newInstance();
System.out.println("CL using system CL: "+c3.getClass().getClassLoader());
// This won't work because the ClassTest is defined in the current CL but I'm trying to assign it to a
// dynamically created instance of ClassTest associated to the system CL so:
// java.lang.ClassCastException: ClassTest cannot be cast to ClassTest
// ClassTest c4 = (ClassTest)ClassLoader.getSystemClassLoader().loadClass("ClassTest").newInstance();
}
public static void main(String[] args) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
CustomClassLoader cl = new CustomClassLoader(Test.class.getClassLoader());
cl.loadClass("ClassLoaderTest").newInstance();
}
}
The output in my case is:
Current CL: CustomClassLoader#1cfb549
Parent CL: sun.misc.Launcher$AppClassLoader#8ed465
CL using forName: CustomClassLoader#1cfb549
CL using new: CustomClassLoader#1cfb549
CL using system CL: sun.misc.Launcher$AppClassLoader#8ed465
I'm using this custom ClassLoader (CL): www.javablogging.com/java-classloader-2-write-your-own-classloader/

A custom String class creation

I tried to create a custom class String in java.lang package in my eclipse workspace.
initially I suspected that a same class in same package can not be created but to my utter surprise I was able to create a class (String) in same package i.e. java.lang
Now I am confused
1) why is it possible and
2) what can be the reason if that is allowed.
3) what will be the use if this type of creation of java classes is allowed in Java.
You can create a new class in java.lang package. If it was forbidden how Oracle developers would be able to develop Java at all? I am sure they use the same javac as we do.
But you will not be able to load it, because java.lang.ClassLoader (that any classloader extends) does not allow it, every class being loaded goes through this check
...
if ((name != null) && name.startsWith("java.")) {
throw new SecurityException
("Prohibited package name: " + name.substring(0, name.lastIndexOf('.')));
}
...
so you will end up in something like
Exception in thread "main" java.lang.SecurityException: Prohibited package name: java.lang
at java.lang.ClassLoader.preDefineClass(ClassLoader.java:649)
at java.lang.ClassLoader.defineClass(ClassLoader.java:785)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:449)
at java.net.URLClassLoader.access$100(URLClassLoader.java:71)
at java.net.URLClassLoader$1.run(URLClassLoader.java:361)
at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
at java.lang.ClassLoader.loadClass(ClassLoader.java:423)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
at java.lang.ClassLoader.loadClass(ClassLoader.java:356)
at Test1.main(Test1.java:11)
As for classes that shadow existing classes like your java.lang.String they cannot be loaded because the System ClassLoader (default one) uses "parent first" strategy, so java.lang classes will be loaded from rt.jar with bootstrap classloader. So you will need to replace String.class in rt.jar with your version. Or override it using -Xbootclasspath/p: java option which prepends paths to bootstrap class loader search paths. So you can
1) copypaste real String.java content into your String.java
2) change a method, eg
public static String valueOf(double d) {
return "Hi";
}
and compile your String.java
3) create a test class
public class Test1 {
public static void main(String[] args) throws Exception {
System.out.println(String.valueOf(1.0d));
}
}
4) run it as
java -Xbootclasspath/p:path_to_your_classes Test1
and you will see
Hi
This is called class shadowing.
1.) It is possible because java classes are not statically linked, but linked at class load time.
2.) If it was not allowed, then the whole class loading would be a lot more difficult to achieve. Then for example you would also have to build your project against a specific Java version. because Java classes may change from version to version. This isn't going to be a maintainable approach.
3.) osgi makes use of this to be able to load different versions of the same bundle. Another common use case is to replace buggy classes in frameworks, where no other workaround is possible. However this technique should be used carefully, because errors might be hard to debug.
Please note that however shadowing classes in the java.* packages is not allowed, as this would break the Java security sandbox. So you are going to have problems at runtime.
Yes you can create the package with name java.lang and also Class named as String.
But you wont be able to run your String class.
1) why is it possible : Compiler will compile your class successfully.
2) what can be the reason if that is allowed : You have a valid name for your package and class so compiler doesn't complain.
3) what will be the use if this type of creation of java classes is allowed in Java : But there is not much use of this String class. Bootstrap class loader will load class from the sun's java.lang package. So your custom String class will not get loaded and hence it fails during run.
Bootstrap class loader is part of JVM implementation and it loads the classes of Java API (which includes java.lang.String). Also for each class which gets loaded, JVM keeps track of which class loader whether bootstrap or user-defined - loaded the class. So any attempt to load a custom String class will fail as String class is already loaded.

Reflection getDeclaredMethods() and class that is not in classpath

I am using reflection to get all methods from a specific class.
This class has references to class that not in my class path so I get an exception:
java.lang.NoClassDefFoundError:
On this:
Method methods[] = theClass.getDeclaredMethods();
Is it possible, somehow,to "skip" everything that is not in classpath?
Class.forName() will not load a class, whether it is or isn't in the classpath. It will only return a handle to a class that is already loaded.
A class gets loaded in one of 2 main ways:
1.)The class is referenced in the import statements(java.lang.* is imported automatically so every class in java.lang package is class-loaded from the start)
2.)A class is loaded using a call from a ClassLoader, in which case all of its dependencies are resolved. and loaded as well
So if you are trying to load a class outside of the classpath, or with dependencies outside the classpath, you need to subclass ClassLoader and tell it how to load your classes and their dependencies.
See ClassLoader specification here: http://docs.oracle.com/javase/1.4.2/docs/api/java/lang/ClassLoader.html
Also, there are ready made subclasses of ClassLoader that may do what you want such as URL ClassLoader which will let you simply point the ClassLoader instance at the path, and load any classes in that path.

Categories