
Recently, I passed the Oracle Certified Professional Java Programmer (formerly Sun Certified) exam, and during the preparation I have completed a huge number of different tasks. Individual tasks in Java sometimes appear in Habré and cause considerable interest, so I decided to share the accumulated and make a small selection.
So, below are a dozen of the more, in my opinion, interesting tasks on Java SE of more than 1000, worked out by me. The difficulty varies from medium to ooooooochen complex. The solution of most tasks practically does not require knowledge of the API, there is enough logic and fundamental principles of Java.
By the way, the complexity of the Oracle Certified Professional Java Programmer exam is much lower than the complexity of this test, so anyone who correctly answers at least half of these questions can safely pass this exam without any preparation.
')
In fact, the number of questions I liked a few times more, so after a week I plan to write a continuation of this topic. If the questions seemed too easy to you, or vice versa, too complex - let me know, we will make adjustments.
ATTENTION: in the second half of the article - answers and detailed explanations of the relevant nuances of JAVA.
Test
In all questions the correct answer is only one.
Question 1
The following code is available:
public class Overload{
public void method(Object o) {
System.out.println("Object");
}
public void method(java.io.FileNotFoundException f) {
System.out.println("FileNotFoundException");
}
public void method(java.io.IOException i) {
System.out.println("IOException");
}
public static void main(String args[]) {
Overload test = new Overload();
test.method(null);
}
}
The result of its compilation and execution will be:
- Compilation error
- Runtime error
- "Object"
- "FileNotFoundException"
- "IOException"
Question 2
Float f1 = new Float(Float.NaN);
Float f2 = new Float(Float.NaN);
System.out.println( ""+ (f1 == f2)+" "+f1.equals(f2)+ " "+(Float.NaN == Float.NaN) );
What will be displayed as a result of executing this piece of code:
- false false
- false true false
- true true false
- false true true
- true true true
Question 3
class Mountain {
static String name = "Himalaya";
static Mountain getMountain() {
System.out.println("Getting Name ");
return null;
}
public static void main(String[ ] args) {
System.out.println( getMountain().name );
}
}
What happens when you try to execute this code:
- “Himalaya” will be displayed but will NOT be displayed “Getting Name„
- “Getting Name” and “Himalaya” will be displayed.
- Nothing will be displayed.
- NullPointerException will be thrown.
- “Getting Name” will be displayed, and then NullPointerException will be thrown.
Question 4
Integer a = 120;
Integer b = 120;
Integer c = 130;
Integer d = 130;
System.out.println(a==b);
System.out.println(c==d);
As a result of the execution of this code will be displayed:
- true true
- false false
- false true
- true false
- a runtime error will occur
Question 5
The previous question had already been raised in the Habré, so this question is for those who were not interested in the previous one:
//In File Other.java
package other;
public class Other { public static String hello = "Hello"; }
//In File Test.java
package testPackage;
import other.*;
class Test{
public static void main(String[] args) {
String hello = "Hello", lo = "lo";
System.out.print((testPackage.Other.hello == hello) + " ");
System.out.print((other.Other.hello == hello) + " ");
System.out.print((hello == ("Hel"+"lo")) + " ");
System.out.print((hello == ("Hel"+lo)) + " ");
System.out.println(hello == ("Hel"+lo).intern());
}
}
class Other { static String hello = "Hello"; }
As a result, we get:
- false true true false true
- false false false false
- true true true true
- true true true true true
- All answers are incorrect.
Question 6
Given method signature:
public static <E extends CharSequence> List<? super E> doIt(List<E> nums)
Which is called something like this:
result = doIt(in);
What type should result and in be?
- ArrayList <String> in; List <CharSequence> result;
- List <String> in; List <Object> result;
- ArrayList <String> in; List result;
- List <CharSequence> in; List <CharSequence> result;
- ArrayList <Object> in; List <CharSequence> result;
Question 7
public static void doIt(String String) { //1
int i = 10;
i : for (int k = 0 ; k< 10; k++) { //2
System.out.println( String + i); //3
if( k*k > 10) continue i; //4
}
}
This code:
- Cannot compile because of row 1
- Will not compile because of line 2
- Will not compile because of line 3
- Will not compile because of line 4
- Will compile and run without problems.
Question 8
public class Main {
static void method(int... a) {
System.out.println("inside int...");
}
static void method(long a, long b) {
System.out.println("inside long");
}
static void method(Integer a, Integer b) {
System.out.println("inside INTEGER");
}
public static void main(String[] args) {
int a = 2;
int b = 3;
method(a,b);
}
}
As a result, we get:
- Compilation error
- Runtime error
- "Inside int ..."
- "Inside long"
- Inside INTEGER
Question 9
class Super { static String ID = "QBANK"; }
class Sub extends Super{
static { System.out.print("In Sub"); }
}
class Test{
public static void main(String[] args) {
System.out.println(Sub.ID);
}
}
As a result of the execution of this code:
- It will not even compile.
- The result depends on the implementation of the JVM
- QBANK will be displayed.
- “In Sub” and “QBANK” will be displayed.
- All answers are incorrect.
Question 10
There are two classes:
//in file A.java
package p1;
public class A{
protected int i = 10;
public int getI() { return i; }
}
//in file B.java
package p2;
import p1.*;
public class B extends A{
public void process(A a) {
ai = ai*2;
}
public static void main(String[] args) {
A a = new B();
B b = new B();
b.process(a);
System.out.println( a.getI() );
}
}
As a result of class B performance, we get:
- “20” will be displayed.
- "10" will be displayed
- Code will not compile
- A runtime error will occur.
- All answers are incorrect.
Caution - Answers
So, check the results:
- four
- 2
- 2
- four
- four
- 3
- five
- four
- 3
- 3
I want to congratulate those who correctly answered most of the questions. You are cool.
Debriefing
So, let's begin.
Question 1
The following code is available:
public class Overload{
public void method(Object o) {
System.out.println("Object");
}
public void method(java.io.FileNotFoundException f) {
System.out.println("FileNotFoundException");
}
public void method(java.io.IOException i) {
System.out.println("IOException");
}
public static void main(String args[]) {
Overload test = new Overload();
test.method(null);
}
}
Probably my favorite question. Most people guess the answer from the 5th time. FileNotFoundException is the last thing you think about when looking at this code. But in fact, everything is simple. To begin with, you can pass null to any method. And then the compiler chooses the narrowest version of the method from the possible. In this case, FileNotFoundException is a subclass of IOException, which, in turn, is a subclass of Object. Therefore, the compiler chooses this method.
Here is a slightly different situation:
public class Overload{
public void method(Object o) {
System.out.println("Object");
}
public void method(String s) {
System.out.println("String");
}
public void method(StringBuffer sb) {
System.out.println("StringBuffer");
}
public static void main(String args[]) {
Overload test = new Overload();
test.method(null);
}
}
At first glance, the code is almost the same, but it will not even compile, since there are two methods at the same hierarchy level, and the compiler cannot choose the most specific of them.
Question 2
Float f1 = new Float(Float.NaN);
Float f2 = new Float(Float.NaN);
System.out.println( ""+ (f1 == f2)+" "+f1.equals(f2)+ " "+(Float.NaN == Float.NaN) );
With the first expression everything seems to be clear. Different objects, therefore false. But then ...
In Java, NaNs are incomparable. But there are two exceptions to the work of the Float class:
- If f1 and f2 both represent Float.NaN, then the equals method returns true, while Float.NaN == Float.NaN is false.
- If f1 contains + 0.0f while f2 contains -0.0f, the equal method returns false, while 0.0f == - 0.0f returns true.
Question 3
class Mountain {
static String name = "Himalaya";
static Mountain getMountain() {
System.out.println("Getting Name ");
return null;
}
public static void main(String[ ] args) {
System.out.println( getMountain().name );
}
}
Everything is simple: for all static fields and methods, the compiler replaces the name of the object with the name of the class, and at run time it does not matter whether the reference was zero or not.
That is, mountain.name changes to Mountain.name.
It is generally recommended when referring to static members of a class to always refer to them through the name of the class, not the object.
Question 4
Integer a = 120;
Integer b = 120;
Integer c = 130;
Integer d = 130;
System.out.println(a==b);
System.out.println(c==d);
This question is familiar to many. For the rest I will tell. For more efficient use of memory, so-called pools are used in Java. There is a string pool, Integer pool, etc. When we create an object without using the new operation, the object is placed in the pool, and subsequently, if we want to create the same object (again without using new), the new object will not be created, and we will simply get a link to our object from the pool.
The Integer-Pool feature is that it stores only numbers that fit into the byte data type: from -128 to 127. For the other numbers, the pool does not work.
Question 5
The same subject, but more difficult:
//In File Other.java
package other;
public class Other { public static String hello = "Hello"; }
//In File Test.java
package testPackage;
import other.*;
class Test{
public static void main(String[] args) {
String hello = "Hello", lo = "lo";
System.out.print((testPackage.Other.hello == hello) + " ");
System.out.print((other.Other.hello == hello) + " ");
System.out.print((hello == ("Hel"+"lo")) + " ");
System.out.print((hello == ("Hel"+lo)) + " "); // runtime
System.out.println(hello == ("Hel"+lo).intern());
}
}
class Other { static String hello = "Hello"; }
All the same string pool, but with nuances.
So, 6 little-known facts about strings in Java:
1. String literals in the same class are links to the same object.
2. String literals in different classes, but in the same package are links to the same object.
3. String literals in different classes and different packages still represent links to the same object)).
4. Strings resulting from addition of constants are calculated at compile time and then see point one.
5. Strings created at runtime do NOT refer to the same object. (so the fourth output is false)
6. The intern method in any case returns an object from the pool, regardless of when the string is created, at the stage of compilation or execution. (Therefore, the last conclusion is true).
This topic is described in more detail in clause 3.10.5 of the Java specification.
Question 6
Given method signature:
public static <E extends CharSequence> List<? super E> doIt(List<E> nums)
Which is called something like this:
result = doIt(in);
What type should result and in be?
- ArrayList <String> in; List <CharSequence> result;
- List <String> in; List <Object> result;
- ArrayList <String> in; List result;
- List <CharSequence> in; List <CharSequence> result;
- ArrayList <Object> in; List <CharSequence> result;
The input parameter was described as List <E>, where E is some class that inherits CharSequence. Thus, ArrayList <String>, List <String>, or List <CharSequence> are suitable options for 'in'.
This method returns a List <? super E>, which means that this is a List containing some kind of superclass E. Moreover, E will be bound to the type that is used for 'in'. For example, if you declared ArrayList <String> in, E would be of type String.
An important point to understand is that it is impossible to determine in advance what the method will return. That is, you cannot specify any of the Java classes here, not even Object.
The only option is to use an untyped list, for example: List result.
This topic is quite complex, and I have thought to devote a separate article to the nuances of working with collections in Java. There I will try to highlight these moments in more detail.
Question 7
public static void doIt(String String) { //1
int i = 10;
i : for (int k = 0 ; k< 10; k++) { //2
System.out.println( String + i); //3
if( k*k > 10) continue i; //4
}
}
This code works).
There is an even more fun example:
class X {
<X> X(X x) {
System.out.println(x);
}
}
This is also the working code that prints any object that you specify in the class X constructor.
Let's return to our task. A string is not a keyword, so it can be used as an identifier. The second point - Java keeps the tag identifiers separate from all other identifiers. Therefore, the use of identical identifiers is allowed.
Question 8
public class Main {
static void method(int... a) {
System.out.println("inside int...");
}
static void method(long a, long b) {
System.out.println("inside long");
}
static void method(Integer a, Integer b) {
System.out.println("inside INTEGER");
}
public static void main(String[] args) {
int a = 2;
int b = 3;
method(a,b);
}
}
In this case, a method that takes the long type is called. This is done for the reason that before the 5th java, there were no methods with a variable number of parameters or automatic packaging. Therefore, in older versions of Java, the long method would be invoked as the only possible one. Since innovations should not affect the execution of the old code, it is logical that the long method is run.
If we had only two methods, “inside int ...” and “inside INTEGER”, the last one would start. Thus, the priority of autopacking in Java is higher than the priority of varargs.
Question 9
class Super { static String ID = "QBANK"; }
class Sub extends Super{
static { System.out.print("In Sub"); }
}
class Test{
public static void main(String[] args) {
System.out.println(Sub.ID);
}
}
Static blocks are started during class initialization. The whole question is when the class is initialized, and this happens in the following cases:
- When a method is called that is directly in this class (and not inherited from the superclass)
- When the constructor of this class is called, or when an array of objects of this class is created
- When a field is read or assigned that is not constant
In this case, none of these three conditions were met, so the Sub class was not initialized.
Question 10
There are two classes:
//in file A.java
package p1;
public class A{
protected int i = 10;
public int getI() { return i; }
}
//in file B.java
package p2;
import p1.*;
public class B extends A{
public void process(A a) {
ai = ai*2;
}
public static void main(String[] args) {
A a = new B();
B b = new B();
b.process(a);
System.out.println( a.getI() );
}
}
This question reflects the important property of the protected access specifier. In all books and articles they write that members with protected access are visible in this package and in subclasses of other packages. But few people specify that outside the package, these members are visible ONLY THROUGH PASSING.
Class B itself has access to the i field, but it cannot call it on another object, as in the example, which leads to a compilation error.
I hope you enjoyed these tasks and their solutions. Soon I will write a continuation of this article, where we will look at other interesting aspects of the JAVA language.
Thanks for attention.