The garbage collector only knows how to release memory allocated with new, so it won’t know how to release the object’s “special” memory
To handle this case, Java provides a method called finalize( ) that you can define for your class. Here’s how it’s supposed to work.
When the garbage collector is ready to release the storage used for your object, it will first call finalize( ),
and only on the next garbage-collection pass will it reclaim the object’s memory. So if you choose to use finalize( ),
it gives you the ability to perform some important cleanup at the time of garbage collection.
2
C’tor can be called from inside C’tor using this operator. And this call should be the first operation in the C’tor.
3
The static methods must not call non-static methods
4
Java has no destructor or similar concept, so you must create an ordinary method to perform this cleanup.
If you put some kind of erasing functionality inside finalize( ), then if an object is garbage collected and finalize( ) is called (there’s no guarantee this
will happen), then the image will first be removed from the screen
5
in Java, objects do not always get garbage collected. Or, put another way:
1. Your objects might not get garbage collected.
2. Garbage collection is not destruction.
3. Garbage collection is only about memory.
6
In contrast, Java doesn’t allow you to create local objects—you must always use new. But in Java, there’s no “delete” to call to release the object,
because the garbage collector releases the storage for you. So from a simplistic standpoint, you could say that because of garbage collection, Java has no destructor.
However, there is a very interesting use of finalize( ) that does not rely on it being called every time. This is the verification of the termination condition[23] of an object
7
An alternative approach is lazy evaluation, which means that the code is not JIT compiled until necessary. Thus, code that never gets executed might
never be JIT compiled. The Java HotSpot technologies in recent JDKs take a similar approach by increasingly optimizing a piece of code each time it is executed, so the
more the code is executed, the faster it gets.
8
Within a class, the order of initialization is determined by the order that the variables are defined within the class. The variable definitions may be scattered throughout and in between method definitions, but the variables are initialized before any methods can be called—even the constructor.
9
Arrays
it’s more limited since the size of the array is determined at compile time. The final comma in the list of initializers is optional. (This feature makes for easier maintenance of long lists.)
Integer[] a = {
new Integer(1),
new Integer(2),
new Integer(3),
};
provides a convenient syntax to create and call methods that can produce the same effect as C’s variable argument lists (known as “varargs” in C). These can include unknown quantities of arguments as well as unknown types. Since all classes are ultimately inherited from the common root class Object
Integer[] b = new Integer[] {
new Integer(1),
print(new Object[] {
new Integer(2),
new Integer(47), new VarArgs(),
new Integer(3),
new Float(3.14), new Double(11.11)
};
});
10
Multidimensional arrays
int[][][] a2 = new int[2][2][4];
int[][] a1 = {
for(int i = 0; i < a1.length; i++) int[][][] a2 = new int[2][2][4]; { 1, 2, 3, },
for(int j = 0; j < a1[i].length; j++)
for(int i = 0; i < a2.length; i++) { 4, 5, 6, }, System.out.println( for(int j = 0; j < a2[i].length; j++) }; “a1[" + i + "][" + j + "] = ” + a1[i][j]); for(int k = 0; k < a2[i][j].length; k++) System.out.println(“a2[" + i + "][" + j + "][" + k + "] = ” + a2[i][j][k]);
11
Each compilation unit must have a name ending in .java, and inside the compilation unit there can be a public class that must have the same name as the file (including capitalization, but excluding the .java filename extension). There can be only one public class in each compilation unit, otherwise the compiler will complain. If there are additional classes in that compilation unit, they are hidden from the world outside that package because they’re not public, and they comprise “support” classes for the main public class.
A library is a group of these class files. Each file has one class that is public (you’re not forced to have a public class, but it’s typical), so there’s one component for each file.
Both of these files are placed in the subdirectory on my system:
C:\DOC\JavaT\com\bruceeckel\simple
If you walk back through this, you can see the package name com.bruceeckel.simple, but what about the first portion of the path? That’s taken care of in the CLASSPATH environment variable, which is, on my machine:
CLASSPATH=.;D:\JAVA\LIB;C:\DOC\JavaT
You can see that the CLASSPATH can contain a number of alternative search paths.
There’s a variation when using JAR files, however. You must put the name of the JAR file in the classpath, not just the path where it’s located. So for a JAR named grape.jar your classpath would include:
CLASSPATH=.;D:\JAVA\LIB;C:\flavors\grape.jar
import com.bruceeckel.simple.*;
CLASSPATH contains one or more directories that are used as roots in a search for .class files. Starting at that root, the interpreter will take the package name and replace each dot with a slash to generate a path name from the CLASSPATH root (so package foo.bar.baz becomes foo\bar\baz or foo/bar/baz or possibly something else, depending on your operating system). This is then concatenated to the various entries in the CLASSPATH. That’s where it looks for the .class file with the name corresponding to the class you’re trying to create. (It also searches some standard directories relative to where the Java interpreter resides).
12
creating an alias for System.out.println( ) to reduce typing. This can be part of a package called tools:
//: com:bruceeckel:tools:P.java
You can use this shorthand to print a String either with a newline (P.rintln( )) or without a newline (P.rint( )).
// The P.rint & P.rintln shorthand.
package com.bruceeckel.tools;
public static void main(String[] args) {
P.rintln(“Available from now on!”);
public class P {
P.rint(“” + 100); // Force it to be a String
public static void rint(String s) {
System.out.print(s);
}
public static void rintln(String s) {
System.out.println(s);
}
} ///:~
13
package c05.dessert;
import c05.dessert.*;
Cookie x = new Cookie();
public class Cookie {
//! x.bite(); // Can’t access
public Cookie() {
System.out.println(“Cookie constructor”);
}
void bite() { System.out.println(“bite”); }
} ///:~
14
The default package
You might be surprised to discover that the following code compiles, even though it would appear that it breaks the rules:
//: c05:Cake.java
In a second file in the same directory:
// Accesses a class in a separate compilation unit.
import com.bruceeckel.simpletest.*;
//: c05:Pie.java
// The other class.
class Cake {
static Test monitor = new Test();
class Pie {
public static void main(String[] args) {
void f() { System.out.println(“Pie.f()”); }
Pie x = new Pie();
} ///:~
x.f();
You might initially view these as completely foreign files, and yet Cake is able to create a Pie object and call its f( ) method! (Note that you must have ‘.’ in your CLASSPATH in order for the files to compile.) You’d typically think that Pie and f( ) have package access and therefore not available to Cake. They do have package access—that part is correct. The reason that they are available in Cake.java is because they are in the same directory and have no explicit package name. Java treats files like this as implicitly part of the “default package” for that directory, and thus they provide package access to all the other files in that directory.
monitor.expect(new String[] {
“Pie.f()”
});
}
} ///:~
15
If you create a new package and inherit from a class in another package, the only members you have access to are the public members of the original package.
protected also gives package access—that is, other classes in the same package may access protected elements.
public class Cookie {
import c05.dessert.*;
public Cookie() {
Cookie x = new Cookie();
System.out.println(“Cookie constructor”);
x.bite(); // granted access
}
protected void bite() {
then bite( ) still has the equivalent of package access within package dessert, but it is also accessible to anyone inheriting from Cookie. However, it is not public.
System.out.println(“bite”);
}
}
16
The final keyword
it says “This cannot be changed.” You might want to prevent changes for two reasons: design or efficiency.
Final data
Many programming languages have a way to tell the compiler that a piece of data is “constant.” A constant is useful for two reasons:
1. It can be a compile-time constant that won’t ever change.
the compiler is allowed to “fold” the constant value into any calculations in which it’s used; that is, the calculation can be performed at compile time, eliminating some run-time overhead.
In Java, these sorts of constants must be primitives and are expressed with the final keyword. A value must be given at the time of definition of such a constant
A field that is both static and final has only one piece of storage that cannot be changed
When using final with object references rather than primitives, the meaning gets a bit confusing. With a primitive, final makes the value a constant, but with an object reference, final makes the reference a constant. Once the reference is initialized to an object, it can never be changed to point to another object.
a private method is automatically final, and is also hidden from the derived class.
private final int VAL_ONE = 9;
private static final int VAL_TWO = 99;
2. It can be a value initialized at run time that you don’t want to change
Blank finals
Java allows the creation of blank finals, which are fields that are declared as final but are not given an initialization value. In all cases, the blank final must be initialized before it is used, and the compiler ensures this. However, blank finals provide much more flexibility in the use of the final keyword
public class BlankFinal {
private final int i = 0; // Initialized final
private final int j; // Blank final
private final Poppet p; // Blank final reference
// Blank finals MUST be initialized in the constructor:
public BlankFinal() {
j = 1; // Initialize blank final
p = new Poppet(1); // Initialize blank final reference
}
Final arguments
Java allows you to make arguments final by declaring them as such in the argument list. This means that inside the method you cannot change what the argument reference points to:
void with(final Gizmo g) {
//! g = new Gizmo(); // Illegal — g is final
}
Final methods
There are two reasons for final methods. The first is to put a “lock” on the method to prevent any inheriting class from changing its meaning. This is done for design reasons when you want to make sure that a method’s behavior is retained during inheritance and cannot be overridden
The second reason for final methods is efficiency. If you make a method final, you are allowing the compiler to turn any calls to that method into inline calls.
final and private
Any private methods in a class are implicitly final. Because you can’t access a private method, you can’t override it. You can add the final specifier to a private method, but it doesn’t give that method any extra meaning.
private final void f() {
System.out.println(“OverridingPrivate.f()”);
}
Final classes
When you say that an entire class is final (by preceding its definition with the final keyword), you state that you don’t want to inherit from this class or allow anyone else to do so.
In other words, for some reason the design of your class is such that there is never a need to make any changes, or for safety or security reasons you don’t want subclassing.
final class Dinosaur {
17
Abstract classes and methods
A class containing abstract methods is called an abstract class. If a class contains one or more abstract methods, the class itself must be qualified as abstract. (Otherwise, the compiler gives you an error message.)
If you inherit from an abstract class and you want to make objects of the new type, you must provide method definitions for all the abstract methods in the base class. If you don’t (and you may choose not to), then the derived class is also abstract, and the compiler will force you to qualify that class with the abstract keyword.
It’s possible to create a class as abstract without including any abstract methods. This is useful when you’ve got a class in which it doesn’t make sense to have any abstract methods, and yet you want to prevent any instances of that class.
18
Interfaces
The interface keyword takes the abstract concept one step further. You could think of it as a “pure” abstract class.
An interface can also contain fields, but these are implicitly static and final. An interface provides only a form, but no implementation.
To create an interface, use the interface keyword instead of the class keyword. Like a class, you can add the public keyword before the interface keyword (but only if that interface is defined in a file of the same name) or leave it off to give package access, so that it is only usable within the same package.
Because an interface has no implementation at all—that is, there is no storage associated with an interface—there’s nothing to prevent many interfaces from being combined.
If you do inherit from a non-interface, you can inherit from only one. All the rest of the base elements must be interfaces.
The fields in an interface are automatically public, so it’s unnecessary to specify that.
Grouping constants
Because any fields you put into an interface are automatically static and final, the interface is a convenient tool for creating groups of constant values, much as you would with an enum in C or C++.
These cannot be “blank finals,” but they can be initialized with nonconstant expressions.
package c08;
public interface Months {
int
JANUARY = 1, FEBRUARY = 2, MARCH = 3,
APRIL = 4, MAY = 5, JUNE = 6, JULY = 7,
AUGUST = 8, SEPTEMBER = 9, OCTOBER = 10,
NOVEMBER = 11, DECEMBER = 12;
}
You can use the constants from outside the package by importing c08.* or c08.Months just as you would with any other package, and referencing the values with expressions like Months.JANUARY.
19
Nesting interfaces
In particular, notice that when you implement an interface, you are not required to implement any interfaces nested within. Also, private interfaces cannot be implemented outside of their defining classes.
class A {
public class BImp implements A.B {
interface B {
public void f() {}
void f();
}
}
public class BImp implements B {
public void f() {}
}
}
Inner classes
It’s possible to place a class definition within another class definition. This is called an inner class. The inner class is a valuable feature because it allows you to group classes that logically belong together and to control the visibility of one within the other. However, it’s important to understand that inner classes are distinctly different from composition.
If you want to make an object of the inner class anywhere except from within a non-static method of the outer class, you must specify the type of that object as OuterClassName.InnerClassName
public class Parcel2 {
public static void main(String[] args) {
class Contents {
Parcel2 p = new Parcel2();
private int i = 11;
Parcel2.Contents c = q.cont();
public int value() { return i; }
}
public void ship(String dest) {
Contents c = cont();
20
Definition: An interface is a named collection of method definitions (without implementations). An interface can also declare constants.
-An interface cannot implement any methods, whereas an abstract class can.
-A class can implement many interfaces but can have only one superclass.
-An interface is not part of the class hierarchy. Unrelated classes can implement the same interface.
21
Serialization & serialVersionUID
serialver foo.Person
generates
foo.Person: static final long serialVersionUID =3734178553292263588L;
A class, before it reads the serialized data from the stream, first checks for the presence of the serialVersionUID field within. If found, its value is written to the stream, instead of one being calculated on the fly. Since the SUID values should now match, there would be no problem in reading in the serialized data.
22 Forcing Finalization and Garbage Collection
System.runFinalization(); – This method calls the finalize methods on all objects that are waiting to be garbage collected.
Running the Garbage Collector – System.gc();
23 Using Properties to Manage Program Attributes
Setting Up Your Properties Object
// create and load default properties
Properties defaultProps = new Properties();
FileInputStream in = new FileInputStream(“defaultProperties”);
defaultProps.load(in);
in.close();
// create program properties with default
Properties applicationProps = new Properties(defaultProps);
// now load properties from last invocation
in = new FileInputStream(“appProperties”);
applicationProps.load(in);
in.close();
Saving Properties
FileOutputStream out = new FileOutputStream(“appProperties”);
applicationProps.store(out, “—No Comment—”);
out.close();
Writing System Properties
myProperties.txt.
subliminal.message=Buy Java Now!
import java.io.FileInputStream;
import java.util.Properties;
public class PropertiesTest {
public static void main(String[] args) throws Exception {
// set up new properties object
// from file “myProperties.txt”
FileInputStream propFile = new FileInputStream(
“myProperties.txt”);
Properties p = new Properties(System.getProperties());
p.load(propFile);
// set the system properties
System.setProperties(p);
// display new properties
System.getProperties().list(System.out);
}
}
Reading System Properties
System.getProperty(“path.separator”);
Tags: java

