Java backward compatibility explanation - java

I have a java class file. I compiled with JVM 7. which I implemented java 1.7 additions like String switchcase, diamond operator. Now I want to run this .class file on java 1.6 JRE. Will it run?
A simple program using string switchcase As I uninstalled 6. Please try it out and give me answer
import java.util.Scanner;
public class Classing
{
public static void main(String[] args)
{
System.out.println("Enter a month to know who you are");
System.out.println("Jan \n Feb \n Mar \n Apr");
Scanner scan=new Scanner(System.in);
String name=scan.nextLine();
System.out.println(fortune(name.toLowerCase()));
}
public static String fortune(String s)
{
switch(s)
{
case "jan":
return "Good guy";
case "feb":
return "Nice guy";
case "mar":
return "Brave guy";
case "apr":
return "Super guy";
}
return " Month out of option"+s;
}
}

Java 7's switch on Strings compiles down to the same bytecodes which the Java 6 (and earlier) JRE executes. The same is true of the diamond operator. These are compiler features, not runtime features.
So while I've never tried, I would expect that if you compile code which uses these features using the Java 7 compiler, it should still run on the Java 6 JRE. Of course, if you try to compile that code using the Java 6 compiler, all you will get is a syntax error.
If you really want to know try it and see!

Even though this question has an accepted answer, according to http://www.oracle.com/technetwork/java/javase/compatibility-417013.html#binary
The class file version for Java SE 7 is 51, as per the JVM Specification, because of the invokedynamic byte code introduced by JSR 292. Version 51 class files produced by the Java SE 7 compiler cannot be used in Java SE 6.

No it will not. Just because of the simple reason that ,JRE7 features are not available on JRE6.

It wont even compile if you just even copy paste the code which you implemented on 1.7 to new class of 1.6 ,because you used features which was introduced in 1.7 only

Related

Java record constructor invisible through reflection

I'm playing with Java 15's new records feature, and how it interacts with reflection. I've run into some strange behaviour, where I can sometimes access a record's constructor via reflection, and sometimes not. For example, given the following Java file:
Recording.java:
public class Recording {
public static void main(String[] args) {
System.out.println("Constructors: " + MainRecord.class.getConstructors().length);
System.out.println("Methods: " + MainRecord.class.getDeclaredMethods().length);
}
record MainRecord(int i, String s) {}
}
This behaves as follows:
❯ javac --enable-preview --release 15 Recording.java
Note: Recording.java uses preview language features.
Note: Recompile with -Xlint:preview for details.
❯ java --enable-preview Recording
Constructors: 0
Methods: 5
In other words, the call to getConstructors() does not find any constructors (while the call to `getDeclaredMethods() does find methods). I don't understand why not, because the constructor does exist:
❯ javap Recording\$MainRecord
Compiled from "Recording.java"
final class Recording$MainRecord extends java.lang.Record {
Recording$MainRecord(int, java.lang.String);
public final java.lang.String toString();
public final int hashCode();
public final boolean equals(java.lang.Object);
public int i();
public java.lang.String s();
}
(Putting the record in a separate Java file gives the same results.)
However, if I do the same from JShell:
❯ jshell --enable-preview
| Welcome to JShell -- Version 15
| For an introduction type: /help intro
jshell> record JShellRecord(int i, String s) {}
| created record JShellRecord
jshell> JShellRecord.class.getConstructors().length
$2 ==> 1
So, now it does find the constructor.
Here's the Java version I'm using:
❯ java -version
openjdk version "15" 2020-09-15
OpenJDK Runtime Environment AdoptOpenJDK (build 15+36)
OpenJDK 64-Bit Server VM AdoptOpenJDK (build 15+36, mixed mode, sharing)
Compiling and running the same program from Java 14 does work:
❯ java -version
openjdk version "14.0.2" 2020-07-14
OpenJDK Runtime Environment AdoptOpenJDK (build 14.0.2+12)
OpenJDK 64-Bit Server VM AdoptOpenJDK (build 14.0.2+12, mixed mode, sharing)
❯ javac --enable-preview --release 14 Recording.java
Note: Recording.java uses preview language features.
Note: Recompile with -Xlint:preview for details.
❯ java --enable-preview Recording
Constructors: 1
Methods: 5
I know that in Java 15, compared to Java 14, a number of restrictions have been put in place regarding reflection on records, but if I read the JEP correctly, those only apply to modification. Finding (and perhaps invoking) a constructor does not seem to apply.
Can anyone tell my what's going on here? What do I need to do to see a record's constructor in Java 15 through reflection?
getConstructors() returns public constructors only. Use getDeclaredConstructors() to get all constructors.
Your declaration record MainRecord(int i, String s) {} lacks the public modifier, so it creates a non-public class and also a non-public constructor. See JLS15-preview, §8.10.4
The implicitly declared canonical constructor has the same access modifier as the record class R, unless the record class lacks an access modifier, in which case the canonical constructor has package access
This does indeed differ from the JDK 14 preview. The beginning of the JDK 15 preview document says:
The changes are the same as those in the first preview of Records in Java SE 14, except for the following:
…
8.10.4 Removed requirement that canonical constructor must be public. Any access modifier must provide at least as much access as the record class. If a canonical constructor is implicitly declared, then its access modifier is the same as the record class.
It seems, top level classes created in JShell are implicitly public.
> jdk-15\bin\jshell --enable-preview
| Welcome to JShell -- Version 15
| For an introduction type: /help intro
jshell> record JShellRecord(int i, String s) {}
| created record JShellRecord
jshell> JShellRecord.class.getConstructors()[0]
$2 ==> public JShellRecord(int,java.lang.String)
jshell> java.lang.reflect.Modifier.isPublic(JShellRecord.class.getModifiers())
$3 ==> true
jshell>

The printf method won't work

This is the second time I've tried to use the PrintWriter#printf method, and I get this error message:
The method printf(String, Object[]) in the type PrintStream is not applicable for the argument (String, String)
The code I'm using has two classes.
This is the first class:
class apples4 {
public static void main(String[] args) {
tuna4 tuna4Object = new tuna4("Kelsey");
tuna4Object.saying();
}
}
This is the second class:
public class tuna4 {
private String girlName;
public tuna4(String name) {
girlName=name;
}
public void setName(String name) {
girlName=name;
}
public String getName() {
return girlName;
}
public void saying(){
System.out.printf("Your first girlfriend was %s\n", getName() );
}
}
Check your compliance level...
PrintStream#printf method is available since Java SE 5. Looks like your code is being compiled/evaluated by Java 4 or prior.
Review your JDK installation and/or your IDE settings about how it is compiling/evaluating your code.
By the way, if using Eclipse and Java 8, Eclipse needs a plugin to recognize Java 8 applications, so by default the evaluator will downgrade your project to Java 1.4. This happened to me and I solved it by installing an update in Eclipse Kepler. Eclipse Luna (latest Eclipse version)says that it supports Java 8, but didn't work for me (not sure if I followed the right steps or did something wrong, but went back to Kepler and works fine).
It might sound weird, but you can cast the return value of your getName() method to Object:
System.out.printf("Your first girlfriend was %s\n", (Object) getName());
Or (to create the requested array) even
System.out.printf("Your first girlfriend was %s\n", new Object[] {(Object) getName()} );
could help.
I'm sorry about my previous post saying I had the same problem, I didn't read the "before you post read this" dialog box that says don't do that. Well, after a lot of time looking around for the answer, I figured it out myself. In Preferences->Java->Compiler box, there is a button in the top left corner called "Configure Project Specific Settings...". Click it and either change the compliance level to >= Java 1.5, or turn it off. Boom, fixed.
you might need to change the execution environment if it's not already java SE 1.8
it might be CDC or sth else , so u need to change it to java SE 1.8
details in picture 1.expand ur project then 2.right click on JRE System Library and choose properties finally 3. if the environment is not java SE 1.8 ,change it to become so

Check java version during program load

I'm looking for a way to check which java version my software is running under.
I'd like to verify during load time my software is running on at least
To get the java version you can use any of these depending on the version you want:
java.specification.version
java.version
java.vm.version
java.runtime.version
However, note that java versions are not equivalent between operative systems. So Java 6 on OSX does not mean the same thing as Java 6 on Windows. So, I would recommend you to also get the OS where the application is running, if you wish to determine if a given feature is available:
System.getProperty("os.name")
As a general guideline, all of this stuff is in the System package. A trick I use is iterate through all the available fields to have an idea of what I can use:
import java.util.Map;
class ShowProperties {
public static void main(String[] args) {
for (Map.Entry<Object, Object> e : System.getProperties().entrySet()) {
System.out.println(e);
}
}
}
Use java.version property to retrieve the jre version.
String javaVersion = System.getProperty("java.version");
if ((!javaVersion.startsWith("1.6")) && (!javaVersion.startsWith("1.7")) && (!javaVersion.startsWith("1.8")) && (!javaVersion.startsWith("1.9")))
{
// error
}
You can use System.getProperty:
System.out.println(System.getProperty("java.version"));
1.7.0_21
java.lang.System.getProperty("java.version")

How to determine the Java byte code version of the current class programatically? [duplicate]

This question already has answers here:
Java API to find out the JDK version a class file is compiled for?
(9 answers)
Closed 9 years ago.
I have a situation where the deployment platform is Java 5 and the development happens with Eclipse under Java 6 where we have established a procedure of having a new workspace created when beginning work on a given project. One of the required steps is therefore setting the compiler level to Java 5, which is frequently forgotten.
We have a test machine running the deployment platform where we can run the code we build and do initial testing on our PC's, but if we forget to switch the compiler level the program cannot run. We have a build server for creating what goes to the customer, which works well, but this is for development where the build server is not needed and would add unnecessary waits.
The question is: CAN I programmatically determine the byte code version of the current class, so my code can print out a warning already while testing on my local PC?
EDIT: Please note the requirement was for the current class. Is this available through the classloadeer? Or must I locate the class file for the current class, and then investigate that?
Easy way to find this to run javap on class
For more details goto http://download.oracle.com/javase/1,5.0/docs/tooldocs/windows/javap.html
Example:
M:\Projects\Project-1\ant\javap -classpath M:\Projects\Project-1\build\WEB-INF\classes -verbose com.company.action.BaseAction
and look for following lines
minor version: 0
major version: 50
You could load the class file as a resource and parse the first eight bytes.
//TODO: error handling, stream closing, etc.
InputStream in = getClass().getClassLoader().getResourceAsStream(
getClass().getName().replace('.', '/') + ".class");
DataInputStream data = new DataInputStream(in);
int magic = data.readInt();
if (magic != 0xCAFEBABE) {
throw new IOException("Invalid Java class");
}
int minor = 0xFFFF & data.readShort();
int major = 0xFFFF & data.readShort();
System.out.println(major + "." + minor);
Take a look at question: Java API to find out the JDK version a class file is compiled for?
here is the Java Class File Format descriptor:
Java Class File Format
and here the major version values:
public static final int JDK14_MAJOR_VERSION = 48;
public static final int JDK15_MAJOR_VERSION = 49;
public static final int JDK16_MAJOR_VERSION = 50;
Now, read the class file with Java code and check the major version to know which JVM generated it
Bytes 5 through 8 of a class file content is the version number in hex. You can use Java code (or any other language) to parse the version number.

Scanner cannot be resolved to a type

I just installed Ubuntu 8.04 and I'm taking a course in Java so I figured why not install a IDE while I am installing it. So I pick my IDE of choice, Eclipse, and I make a very simple program, Hello World, to make sure everything is running smoothly. When I go to use Scanner for user input I get a very odd error:
My code:import java.util.Scanner;
class test {
public static void main (String [] args) {
Scanner sc = new Scanner(System.in);
System.out.println("hi");
}
}
The output:
Exception in thread "main" java.lang.Error: Unresolved compilation problems:
Scanner cannot be resolved to a type
Scanner cannot be resolved to a type
at test.main(test.java:5)
The Scanner class is new in Java 5. I do not know what Hardy's default Java environment is, but it is not Sun's and therefore may be outdated.
I recommend installing the package sun-java6-jdk to get the most up-to-date version, then telling Eclipse to use it.
If you are using a version of Java before 1.5, java.util.Scanner doesn't exist.
Which version of the JDK is your Eclipse project set up to use?
Have a look at Project, Properties, Java Build Path -- look for the 'JRE System Library' entry, which should have a version number next to it.
It could also be that although you are have JDK 1.5 or higher, the project has some specific settings set that tell it to compile as 1.4. You can test this via Project >> Properties >> Java Compiler and ensure the "Compiler Compliance Level" is set to 1.5 or higher.
I know, It's quite a while since the question was posted. But the solution may still be of interest to anyone out there. It's actually quite simple...
Under Ubuntu you need to set the java compiler "javac" to use sun's jdk instead of any other alternative. The difference to some of the answers posted so far is that I am talking about javac NOT java. To do so fire up a shell and do the following:
As root or sudo type in at command line:
# update-alternatives --config javac
Locate the number pointing to sun's jdk, type in this number, and hit "ENTER".
You're done! From now on you can enjoy java.util.Scanner under Ubuntu.
System.out.println("Say thank you, Mr.");
Scanner scanner = java.util.Scanner(System.in);
String thanks = scanner.next();
System.out.println("Your welcome.");
You imported Scanner but you're not using it. You're using Scanner, which requires user inputs. You're trying to print out one thing, but you're exposing the your program to the fact that you are going to use your own input, so it decides to print "Hello World" after you give a user input. But since you are not deciding what the program will print, the system gets confused since it doesn't know what to print. You need something like int a=sc.nextInt(); or String b=sc.nextLine(); and then give your user input. But you said you want Hello World!, so Scanner is redundant.
package com.company;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
System.out.print("Input seconds: ");
int num = in.nextInt();
for (int i = 1; i <=num; i++) {
if(i%10==3)
{
System.out.println(i);
}
}
}
}

Categories

Resources