Oracle Certified Professional Java Programmer Exam Preparation Part 1

    Foreword



    I want to continue to share the acquired knowledge and my impressions of preparing for the exam. Many thanks to all those who made recommendations for the zero part of this series! Today I’ll talk a little more about access modifiers and their relationship with inheritance and packages, consider varargs and enumerations, as well as arrays and ways to initialize them. I hope that the harazhiteli again respond and complement what I forgot to mention or simply did not know.

    We continue to prepare for the exam under the cut.



    Content for the entire series


    1. Identifiers, naming rules, modifiers for classes and interfaces
    2. Modifiers for methods and fields, vararg, enum and arrays


    Methods, fields, local variables and their modifiers



    As I said, in Java there are four access modifiers: public, private, protected and the lack of a modifier (it is the default modifier). Only two of them apply to non-nested classes and interfaces: public and the default modifier. The whole set is applicable to the methods and fields of the class.

    1. If a method or field has a public modifier, then they are potentially available to the entire universe.
    2. If a method or field has a private access modifier, then they are available only within the class. Such members of the class are not inherited, so they cannot be replaced in subclasses. Remember this.
    3. If a method or field has a default access modifier, then they are available only within the package.
    4. If a method or field has a protected access modifier, then they are primarily accessible to the class itself and its descendants. In addition, access to these members of the class can get their brothers in the package.


    Checking the code proposed as part of the exam, you should be careful. Always pay attention to both the method or field access modifier and the class access modifier. You can often find a situation where the method has a public modifier, while the class containing it is accessible only from the package. In this situation, the method from outside the package will not be available. You can easily get a minus without paying attention to this detail.

    I also want to pay attention to some features that arise when using the default access and the protected modifier. Consider the following example. Let there be a base class declared in the test package. This class has two fields. The first is declared with default access, the second is protected.

    package org.kimrgrey.scjp.test;
    public class BaseClass {
            int defaultValue;
            protected int protectedValue;
            public BaseClass() {
                    this.defaultValue = 1;
                    this.protectedValue = 1;
            }
    }
    


    If you declare the SamePackageAccess class in this package, which will not inherit from BaseClass, it will still get access to both the defaultValue field and the protectedValue field. It is worth remembering about this feature of the protected modifier: class members declared as protected within the package are available both through inheritance and through a link. Example: In the case of inheritance in this package, access is still saved to both fields, both by reference and through inheritance.

    package org.kimrgrey.scjp.test;
    public class SamePackageAccess {
            public SamePackageAccess() {
                    BaseClass a = new BaseClass();
                    a.defaultValue = 2;
                    a.protectedValue = 2;
            }
    }
    




    package org.kimrgrey.scjp.test;
    public class SamePackageSubclass extends BaseClass {
            public SamePackageSubclass() {
                    this.defaultValue = 3;
                    this.protectedValue = 3;
                    BaseClass a = new BaseClass();
                    a.defaultValue = 3;
                    a.protectedValue = 3;
            }
    }
    


    Now let's see what happens if we go beyond the package. The first thing that happens is that we will lose access to the field declared without explicitly specifying the access modifier. Absolutely all classes outside the native package will not see it, including the direct descendants of BaseClass. A field with the protected modifier will be available through inheritance to all its subclasses. However, even the heir will not be able to use it through the link. In addition, once a class is inherited outside the package, the field becomes closed to any classes, with the exception of further descendants. This example also contains another important detail. Suppose you are asked what happens if you compile the above code? And give the following answer options:

    package org.kimrgrey.scjp.main;
    import org.kimrgrey.scjp.test.BaseClass;
    public class OtherPackageSubclass extends BaseClass {
            public OtherPackageSubclass() {
                    this.defaultValue = 10; // Line 8: не получим доступ, потому что другой пакет
                    this.protectedValue = 10;
                    BaseClass a = new BaseClass();
                    a.protectedValue = 10; // Line 12: по ссылке не могут обращаться даже наследники BaseClass
            }
    }
    



    1. The code will be compiled successfully
    2. A compilation error occurs on line number 8
    3. A compilation error will occur on line number 12

    In this case, unless the contrary is explicitly stated, you need to select all the correct answer options: 2 and 3, and not stop at the first suitable one. Read all the answers carefully and check for correctness. It is this approach that works best. After reading and understanding the essence of the question, check and analyze the answers, not the code given in the wording.

    Among the modifiers associated with inheritance, final should also be considered. Final acts on methods the same way as on classes: prohibits their redefinition by heirs. At the same time, it is still possible to extend the class itself in which the final method is located.

    You can apply the final modifier to fields, method arguments, and local variables. In the case of primitive types, any change in the value of a variable will be prohibited, except for its initialization. It should be remembered that the moment of initialization of local variables is considered the first assignment of values ​​to them within the framework of the method. Prior to this, the variable cannot be used: get a compilation error. A marked final field will also have to be explicitly initialized. This can be done either directly during the declaration, in the initialization block, or in the constructor of the class in which it is declared. Leaving the initialization of final fields to the conscience of the heirs is not allowed. For links, the final modifier prohibits reassignment of the link. The object that the link points to can still be changed: call methods that change its state,

    It is important to remember that no modifiers other than final are applicable to local variables. Therefore, if you see something like in the local variable declaration private int a, then you can safely say that this will not compile. But what about the fields?
    1. As I said before, all four levels of access are applicable to fields.
    2. The field may be marked final.
    3. The field may be marked as transient.
    4. The field can be marked as static.
    5. The field may be marked as volatile.
    6. The field cannot be marked as abstract.
    7. The field cannot be marked as synchronized.
    8. The field cannot be marked as strictfp.
    9. The field cannot be marked as native.

    Some of the modifiers mentioned above, I have not described before. I will try to consider them later in the relevant topics (transient will be considered as part of serialization, and synchronized and volatile in multithreading).

    Variable Argument Methods


    1. When you specify the vararg parameter, then the base type can be any type: primitive or not.
    2. To declare such a parameter, you are writing the type, then three points, a space, then the name of the array that will be used within the method: void f (int... a). You can also split the type of three points and identifkatory spaces, as follows: void f(int ... a). Watch the dots carefully. Exam authors like to transfer them by identifier. This approach does not work.
    3. Other parameters may be passed to the method, but in this case the vararg parameter should be the last: void f (double x, int... a)
    4. There can be one and only one vararg parameter in a method.

    For clarity, I will give a good example of a question on this topic. Choose a declaration to the doSomething () method so that the code below compiles successfully?

    package org.kimrgrey.scjp.main;
    public class Application {
            public static void main(String[] args) {
                    doSomething(1);
                    doSomething(1, 2);
            }
    }
    


    1. static void doSomething(int... values) {}
    2. static void doSomething(int[] values) {}
    3. static void doSomething(int x, int... values) {}


    The first and third options are correct. Both that, and another are correct both from the point of semantics of a call, and from the point of view of syntax. Using the array as a type to pass several parameters is so simple. But the opposite is not true. Example: Everything will wonderfully assemble and work. I do not know a formal explanation for this, but I suppose that this is due to the fact that the vararg parameter is just syntactic sugar and is perceived by the compiler as a reference to an array, so there are no problems.

    package org.kimrgrey.scjp.main;
    public class Application {
            private static void f (int... a) {
                    for (int i = 0; i < a.length; ++i) {
                            System.out.println(a[i]);
                    }
            }
            public static void main(String[] args) {
                    f(new int[] {1, 2 ,3});
            }
    }
    




    Transfers


    1. Enumerations can have constructors.
    2. Enumerations can have fields.
    3. Enumerations can have methods.
    4. If an enumeration is declared outside the class, it can get only two access levels: public or default.
    5. Enumerations have a static method values()that returns an array containing all possible values ​​of the enumeration, and strictly in the order in which they were declared.

    For each of the values ​​within the enumeration, you can declare your own “body” - its specific description. Moreover, value-specific versions of the methods overload the version that is used for the entire enumeration as a whole. This allows you to change the behavior of enumeration members depending on the needs of the application. Example: As a result of executing this code, the string “USD” will be placed in the standard output stream. Pay attention to the getSomethingElse () method. It is declared for the value of USD, but is not mentioned for the entire listing. Despite the fact that the ad is public, no one from outside can access this method. If line 44 is uncommented, the code will not even compile.

    package org.kimrgrey.scjp.main;
    import static java.lang.System.*;
    enum Currency {
            UNKNOWN,
            USD {
                    public String getStringCode() {
                            return "USD";
                    }
                    public int getSomethingElse() {
                            return 10;
                    }
            },
            UAH {
                    public String getStringCode() {
                            return "UAH";
                    }
            },
            RUR {
                    public String getStringCode() {
                            return "RUR";
                    }
            };
            public String getStringCode() {
                    return "";
            }
    }
    public class Application {
            private static void f (int... a) {
                    for (int i = 0; i < a.length; ++i) {
                            out.println(a[i]);
                    }
            }
            public static void main(String[] args) {
                    out.println(Currency.USD.getStringCode());
                    // out.println(Currency.USD.getSomethingElse());
            }
    }
    





    A bit about arrays



    There are two options for declaring arrays in Java. The brackets can be placed after the name of the type, as follows: int[] a- or after the identifier, as follows: int a[]. It is important to understand that both methods are absolutely equal in terms of syntax, although the first one is recommended. Thus, String[] s[]it is nothing more than a two-dimensional array of strings. Compiles without question.

    When declaring an array can not specify its size, since memory is allocated only when you create an array: int[] a = new int [4]. Therefore, the code int a[4]will cause a compilation error. In the case of an array of object references, it is important to remember that when creating an array, the objects themselves are not created. For example, the code Thread threads = new Thread [20]will create an array of twenty nulls, no constructors will be called.

    When building multidimensional arrays, you need to think of them as arrays, each element of which refers again to the array. Abstract constructions like matrices and cubes simplify programming, but can make exam passing difficult. For example, the design int [][]a = new int [10][]is quite acceptable and create a two-dimensional array whose elements can be initialized later: a[0] = new int [100]- said arrays are not necessarily of equal length: a[1] = new int [200].

    To initialize an array of fast (not item by item), you can use syntax like this: int[] x ={1, 2, 3}. In curly brackets can be not only constants, but also variables and even expressions. You can also create anonymous arrays, which is often used when you need to pass a strictly defined array to a function:f(new int [] {2, 4, 8}). If you see such a design in the exam, then be sure to take a closer look. It is likely that it will be written something like this: f(new int[3] {2, 4, 8}). Such code will not be compiled, since the size of the anonymous array is calculated based on its declaration and should not be specified explicitly.

    On this I will end for today. In the near future, we will definitely talk about the features of some important operations in Java (assignment, comparison, instanceOf, arithmetic), as well as about implicit classes and streams.

    Also popular now: