@TaoSama
2018-03-19T11:53:25.000000Z
字数 37688
阅读 1039
Java
Write above:
I wrote the notes in the view of a CPP programmer,
which is quick for catching the differences.
Any error plz point out.
Java, the library has different types of containers for different needs:
One of the big changes in Java SE5 is the addition of parameterized types, called generics in Java。
ArrayList<Shape> shapes = new ArrayList<Shape>();
Java’s concurrency is built into the language, and Java SE5 has added significant additional library support.
Plug-ins and Scripting languages.
A safer practice, then, is always to initialize a reference when you create it:
String s = "asdf";
Primitive type | Size | Minimum | Maximum | Wrapper type |
---|---|---|---|---|
boolean | — | — | — | Boolean |
char | 16 bits | Unicode 0 | Unicode 2^16- | 1 |
byte | 8 bits | -128 | +127 | Byte |
short | 16 bits | -2^15 | +2^15-1 | Short |
int | 32 bits | -2^31 | +2^31-1 | Integer |
long | 64 bits | -2^63 | +2^63-1 | Long |
float | 32 bits | IEEE754 | IEEE754 | Float |
double | 64 bits | IEEE754 | IEEE754 | Double |
void | — | — | — | Void |
// The “wrapper” classes allow you to make a non-primitive object on the heap
// to represent a primitive type.
Character ch = new Character(‘x’);
// Java SE5 autoboxing will automatically convert from a primitive to a wrapper type:
Character ch = ‘x’;
// and back:
char c = ch;
BigInteger
and BigDecimal
In C, C++, and Java, scope is determined by the placement of curly braces {}
int x = 12;
// Only x available
{
int q = 96;
// Both x & q available
// You cannot do the following, even though it is legal in C and C++:
int x = 96; // Illegal
}
// Only x available
// q is "out of scope"
}
{
String s = new String("a string");
} // End of scope
class DataOnly {
int i;
double d;
boolean b;
}
DataOnly data = new DataOnly();
data.i = 47;
data.d = 1.1;
data.b = false;
When a primitive data type is a member of a class, it is guaranteed to get a default value if you do not initialize it:
Primitive type | Default |
---|---|
boolean | false |
char | ‘\u0000’(null) |
byte | (byte)0 |
short | (short)0 |
int | 0 |
long | 0L |
float | 0.0f |
double | 0.0d |
This guarantee doesn’t apply to local variables those that are not fields of a class.
int x;
x
will get some arbitrary value (as in C and C++);
// HelloDate.java
import java.util.*;
public class HelloDate {
public static void main(String[] args) {
System.out.println("Hello, it’s: ");
System.out.println(new Date());
}
}
java.lang
is implicitly included in every Java code file, these classes are automatically available. java.util.Date
is in the util library and that you must import java.util.*
in order to use Date
.
javac HelloDate.java
java HelloDate
/* This is a comment
* that continues
* across lines
*/
// Remember, however, that everything inside the /* and */ is ignored,
// so there’s no difference in saying:
/* This is a comment that
continues across lines */
// This is a one-line comment
//: object/Documentation1.java
/** A class comment */
public class Documentation1 {
/** A field comment */
public int i;
/** A method comment */
public void f() {}
} ///:~
//: object/Documentation2.java
/**
* <pre>
* System.out.println(new Date());
* </pre>
*/
///:~
@see classname
@see fully-qualified-classname
@see fully-qualified-classname#method-name
{@link package.class#member label}
{@docRoot}
{@inheritDoc}
@version version-information
@author author-information
@since version-information
@param parameter-name description
@return description
@throws fully-qualified-class-name description
@deprecated
class AllTheColorsOfTheRainbow {
int anIntegerRepresentingColors;
void changeTheHueOfTheColor(int newHue) {
// ...
}
// ...
}
Short-circuiting
float f4 = 1e-43f;
round( )
methods in java.lang.Math
.range-based for
in cpp11
.
label1:
outer-iteration {
inner-iteration {
//...
break; // (1)
//...
continue; // (2)
//...
continue label1; // (3)
//...
break label1; // (4)
}
}
switch(integral-selector) {
case integral-value1 : statement; break;
case integral-value2 : statement; break;
case integral-value3 : statement; break;
case integral-value4 : statement; break;
case integral-value5 : statement; break;
// ...
default: statement;
}
The this
keyword which can be used only inside a non-static method produces the reference to the object that the method has been called for.
new
, so it won’t know how to release the object’s “special” memory. finalize()
that you can define for your class.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.
finalize()
directly, so that’s not a solution. finalizie()
can be used as the verification of the termination condition of an object.
Adaptive generational stop-and-copy mark-and-sweep.
public class InitialValues2 {
boolean bool = true;
char ch = ‘x’;
byte b = 47;
short s = 0xff;
int i = 999;
long lng = 1;
float f = 3.14f;
double d = 3.14159;
}
To summarize the process of creating an object, consider a class called Dog
:
static
keyword, the constructor is actually a static method. Dog
is created, or the first time a static method or static field of class Dog is accessed, the Java interpreter must locate Dog.class
, which it does by searching through the classpath.Dog.class
is loaded (creating a Class object
, which you’ll learn about later), all of its static initializers are run. Class object
is loaded for the first time.new Dog()
, the construction process for a Dog object first allocates enough storage for a Dog object
on the heap.
public class Spoon {
static int i;
static {
i = 47;
}
}
public class Mugs {
Mug mug1;
Mug mug2;
{
mug1 = new Mug(1);
mug2 = new Mug(2);
print("mug1 & mug2 initialized");
}
}
int[] a = { 1, 2, 3, 4, 5 };
In Java SE5, however, this long-requested feature was finally added, so you can now use
ellipses to define a variable argument list.
public class NewVarArgs {
static void printArray(Object... args) {
for(Object obj : args)
System.out.print(obj + " ");
System.out.println();
}
}
public enum Spiciness {
NOT, MILD, MEDIUM, HOT, FLAMING
}
public class EnumOrder {
public static void main(String[] args) {
for(Spiciness s : Spiciness.values())
System.out.println(s + ", ordinal " + s.ordinal());
}
}
/* Output:
NOT, ordinal 0
MILD, ordinal 1
MEDIUM, ordinal 2
HOT, ordinal 3
FLAMING, ordinal 4
*/
class WaterSource {
private String s;
WaterSource() {
System.out.println("WaterSource()");
s = "Constructed";
}
public String toString() { return s; }
}
class Art {
Art() { print("Art constructor"); }
}
class Drawing extends Art {
Drawing() { print("Drawing constructor"); }
}
public class Cartoon extends Drawing {
public Cartoon() { print("Cartoon constructor"); }
public static void main(String[] args) {
Cartoon x = new Cartoon();
}
}
/* Output:
Art constructor
Drawing constructor
Cartoon constructor
*/
super
keyword and the appropriate argument list.
class Game {
Game(int i) {
print("Game constructor");
}
}
class BoardGame extends Game {
BoardGame(int i) {
super(i);
print("BoardGame constructor");
}
}
public class Chess extends BoardGame {
Chess() {
super(11);
print("Chess constructor");
}
public static void main(String[] args) {
Chess x = new Chess();
}
}
/* Output:
Game constructor
BoardGame constructor
Chess constructor
*/
public class SpaceShipDelegation {
private String name;
private SpaceShipControls controls = new SpaceShipControls();
public SpaceShipDelegation(String name) {
this.name = name;
}
// Delegated methods:
public void back(int velocity) {
controls.back(velocity);
}
public void down(int velocity) {
controls.down(velocity);
}
public void forward(int velocity) {
controls.forward(velocity);
}
public void left(int velocity) {
controls.left(velocity);
}
public void right(int velocity) {
controls.right(velocity);
}
public void turboBoost() {
controls.turboBoost();
}
public void up(int velocity) {
controls.up(velocity);
}
}
If you want cleanup to take place, make your own cleanup methods and don’t use on finalize()
.
In general, you should follow the same form that is imposed by a C++ compiler on its destructors:
First perform all of the cleanup work specific to your class, in the reverse order of creation. (In general, this requires that base-class elements still be viable.)
Then call the base-class cleanup method.
@Override
annotation, which is not a keyword but can be used as if it were. @Override
.It is the same as C++, but provide package access.
Java SE5 adds covariant return types, which means that an overridden method in a derived class can return a type derived from the type returned by the base-class method.
A general guideline is “Use inheritance to express differences in behavior, and fields to
express variations in state.”
"is-a" vs "is-like-a"
ClassCastException
.
abstract class Instrument {
// You can create an abstract class with no abstract methods
}
interface Instrument { // Automatically public
// Compile-time constant:
int VALUE = 5; // static & final
// Cannot have method definitions:
void play(Note n); // Automatically public
void adjust();
}
class Wind implements Instrument {
public void play(Note n) {} // Must be public
public String toString() {}
public void adjust() {}
public interface Processor {
String name();
Object process(Object input);
}
// Strategy pattern
public class Apply {
public static void process(Processor p, Object s) {
print("Using Processor " + p.name());
print(p.process(s));
}
}
// If you cannot modify the class, use Adapter pattern
public class Filter {
public String name() {
return getClass().getSimpleName();
}
public Waveform process(Waveform input) { return input; }
}
class FilterAdapter implements Processor {
Filter filter;
public FilterAdapter(Filter filter) {
this.filter = filter;
}
public String name() { return filter.name(); }
public Waveform process(Object input) {
return filter.process((Waveform)input); // Delegation
}
}
public class FilterProcessor {
public static void main(String[] args) {
Waveform w = new Waveform();
Apply.process(new FilterAdapter(new Filter(), w);
}
}
interface Monster {
void menace();
}
interface DangerousMonster extends Monster {
void destroy();
}
class DragonZilla implements DangerousMonster {
public void menace() {}
public void destroy() {}
}
public interface RandVals {
Random RAND = new Random(47);
int RANDOM_INT = RAND.nextInt(10);
long RANDOM_LONG = RAND.nextLong() * 10;
float RANDOM_FLOAT = RAND.nextLong() * 10;
double RANDOM_DOUBLE = RAND.nextDouble() * 10;
}
Factory Method design pattern
interface Game { boolean move(); }
interface GameFactory { Game getGame(); }
class Checkers implements Game {
private int moves = 0;
private static final int MOVES = 3;
public boolean move() {
print("Checkers move " + moves);
return ++moves != MOVES;
}
}
class CheckersFactory implements GameFactory {
public Game getGame() { return new Checkers(); }
}
public class Games {
public static void playGame(GameFactory factory) {
Game s = factory.getGame();
while(s.move());
}
public class Sequence {
private Object[] items;
private int next = 0;
public Sequence(int size) { items = new Object[size]; }
public void add(Object x) {
if(next < items.length)
items[next++] = x;
}
private class SequenceSelector implements Selector {
private int i = 0;
public boolean end() { return i == items.length; }
public Object current() { return items[i]; }
public void next() { if(i < items.length) i++; }
}
public Selector selector() {
return new SequenceSelector();
}
public class DotThis {
public class Inner {
public DotThis outer() {
return DotThis.this;
// A plain "this" would be Inner’s "this"
}
}
public class DotNew {
public class Inner {}
public static void main(String[] args) {
DotNew dn = new DotNew();
DotNew.Inner dni = dn.new Inner();
}
}
With interface, it can hide the implementation.
public class Wrapping {
private int i;
public Wrapping(int x) { i = x; }
public int value() { return i; }
}
public class Parcel8 {
public Wrapping wrapping(int x) {
final int y = 47;
// Base constructor call:
return new Wrapping(x) { // Pass constructor argument.
public int value() {
return super.value() * y;
}
}
}; // Semicolon required
}
interface Game { boolean move(); }
interface GameFactory { Game getGame(); }
class Checkers implements Game {
private int moves = 0;
private static final int MOVES = 3;
public boolean move() {
print("Checkers move " + moves);
return ++moves != MOVES;
}
private static GameFactory factory = new GameFactory() {
public Game getGame() { return new Checkers(); }
};
public static GameFactory gameFactory() {
return factory;
}
}
public class Games {
public static void playGame(GameFactory factory) {
Game s = factory.getGame();
while(s.move());
}
interface Incrementable {
void increment();
}
// If your class must implement increment() in
// some other way, you only can use an inner class:
class Callee2 extends MyIncrement {
private int i = 0;
public void increment() {
super.increment();
i++;
print(i);
}
private class Closure implements Incrementable {
public void increment() {
// Specify outer-class method, otherwise
// you’d get an infinite recursion:
Callee2.this.increment();
}
}
Incrementable getCallbackReference() {
return new Closure();
}
}
class Caller {
private Incrementable callbackReference;
Caller(Incrementable cbh) { callbackReference = cbh; }
void go() { callbackReference.increment(); }
}
public class GreenhouseControls extends Controller {
private boolean light = false;
public class LightOn extends Event {
public LightOn(long delayTime) { super(delayTime); }
public void action() {
light = true;
}
public String toString() { return "Light is on"; }
}
public class LightOff extends Event {
public LightOff(long delayTime) { super(delayTime); }
public void action() {
light = false;
}
public String toString() { return "Light is off"; }
}
class WithInner {
class Inner {}
}
public class InheritInner extends WithInner.Inner {
//! InheritInner() {} // Won’t compile
InheritInner(WithInner wi) {
wi.super();
}
public static void main(String[] args) {
WithInner wi = new WithInner();
InheritInner ii = new InheritInner(wi);
}
}
class Egg2 {
protected class Yolk {
public Yolk() { print("Egg2.Yolk()"); }
public void f() { print("Egg2.Yolk.f()");}
}
private Yolk y = new Yolk();
public Egg2() { print("New Egg2()"); }
public void insertYolk(Yolk yy) { y = yy; }
public void g() { y.f(); }
}
public class BigEgg2 extends Egg2 {
public class Yolk extends Egg2.Yolk {
public Yolk() { print("BigEgg2.Yolk()"); }
public void f() { print("BigEgg2.Yolk.f()"); }
}
public BigEgg2() { insertYolk(new Yolk()); }
public static void main(String[] args) {
Egg2 e2 = new BigEgg2();
e2.g();
}
}
$
, followed by the name of the inner class. $
and the outer-class identifier(s). ArrayList
LinkedList
Collection.iterator()
next()
hasNext()
remove()
hasPrevious()
previous()
Set<Integer> intset = new HashSet<Integer>();
SortedSet<Integer> intset = new TreeSet<Integer>();
HashMap
LinkedHashMap
Producing an Iterator
is the least-coupled way of connecting a sequence to a method that consumes that sequence, and puts far fewer constraints on the sequence class than does implementing Collection.
public class CollectionSequence
extends AbstractCollection<Pet> {
private Pet[] pets = Pets.createArray(8);
public int size() { return pets.length; }
public Iterator<Pet> iterator() {
return new Iterator<Pet>() {
private int index = 0;
public boolean hasNext() {
return index < pets.length;
}
public Pet next() { return pets[index++]; }
public void remove() { // Not implemented
throw new UnsupportedOperationException();
}
};
}
}
class PetSequence {
protected Pet[] pets = Pets.createArray(8);
}
public class NonCollectionSequence extends PetSequence {
public Iterator<Pet> iterator() {
return new Iterator<Pet>() {
private int index = 0;
public boolean hasNext() {
return index < pets.length;
}
public Pet next() { return pets[index++]; }
public void remove() { // Not implemented
throw new UnsupportedOperationException();
}
};
}
}
Java SE5 introduced a new interface called Iterable
which contains an iterator()
method to produce an Iterator
, and the Iterable
interface is what foreach
uses to move through a sequence. So if you create any class that implements Iterable
, you can use it in a foreach
statement.
class ReversibleArrayList<T> extends ArrayList<T> {
public ReversibleArrayList(Collection<T> c) { super(c); }
public Iterable<T> reversed() {
return new Iterable<T>() {
public Iterator<T> iterator() {
return new Iterator<T>() {
int current = size() - 1;
public boolean hasNext() { return current > -1; }
public T next() { return get(current--); }
public void remove() { // Not implemented
throw new UnsupportedOperationException();
}
};
}
};
}
}
ReversibleArrayList<String> ral =
new ReversibleArrayList<String>(
Arrays.asList("To be or not to be".split(" ")));
for(String s : ral.reversed())
System.out.print(s + " ");
The try block and exception handler
try {
// Code that might generate exceptions
} catch(Type1 id1)|{
// Handle exceptions of Type1
} catch(Type2 id2) {
// Handle exceptions of Type2
} catch(Type3 id3) {
// Handle exceptions of Type3
}
Maybe the best practice for logging stacktrace of log4j2
in some version.
logger.info("{}", e.toString(), e);
try {
// The guarded region: Dangerous activities
// that might throw A, B, or C
} catch(A a1) {
// Handler for situation A
} catch(B b1) {
// Handler for situation B
} catch(C c1) {
// Handler for situation C
} finally {
// Activities that happen every time
}
try {
// ... to do something useful
} catch(IDontKnowWhatToDoWithThisCheckedException e) {
throw new RuntimeException(e);
}
You can also use e.getCause()
to extract the originating exceptions.
StringBuilder
was introduced in Java SE5. StringBuffer
, which ensured thread safety (see the Concurrency chapter) and so was significantly more expensive. Thus, string operations in Java SE5/6 should be faster.
public class InfiniteRecursion {
public String toString() {
return " InfiniteRecursion address: " + this + "\n";
}
}
System.out.format("Row 1: [%d %f]\n", x, y);
// A nostalgic way
System.out.printf("Row 1: [%d %f]\n", x, y);
Formatter formatter = new Formatter(System.out);
formatter.format("%s The Turtle is at (%d,%d)\n", name, x, y);
// It can come in handy when you only need to call format() once.
String.format("%s The Turtle is at (%d,%d)\n", name, x, y);
java.util.regex.*
\\
means "I want to insert a plain old (literal) backslash in the regular expression. Don’t give it any special meaning." \\
means "I’m inserting a regular expression backslash, so that the following character has special meaning." \\d
. * If you want to insert a literal backslash, you say \\\\
.\n\t
. Efficiency?
StringTokenizer
.Scanner
objects, you can also split a string into parts using more complex patterns—something that’s difficult with StringTokenizer
. StringTokenizer
is obsolete.
// Static method
Class.forName(String)
// Fully qualified name
getName()
// Fully qualified name (introduced in Java SE5)
getCanonicalName()
getSimpleName()
getInterfaces()
islnterface()
getSuperClass()
Class intClass = int.class;
Class<Integer> genericIntClass = int.class;
genericIntClass = Integer.class; // Same thing
Class<Number> genericNumberClass = int.class;
// The wildcard symbol is ‘?’, and it indicates "anything."
Class<?> intClass = int.class;
Class<? extends Number> bounded = int.class;
public class FilledList<T> {
private Class<T> type;
public FilledList(Class<T> type) { this.type = type; }
public List<T> create(int nElements) {
List<T> result = new ArrayList<T>();
try {
for(int i = 0; i < nElements; i++)
result.add(type.newInstance());
} catch(Exception e) {
throw new RuntimeException(e);
}
return result;
}
public static void main(String[] args) {
FilledList<CountedInteger> fl =
new FilledList<CountedInteger>(CountedInteger.class);
System.out.println(fl.create(15));
}
}
// Java SE5 introduces the two below.
Class.cast()
Class.asSubclass()
Class.isisInstance
vs keyword instanceof
class Part {
public String toString() {
return getClass().getSimpleName();
}
static List<Factory<? extends Part>> partFactories =
new ArrayList<Factory<? extends Part>>();
static {
// Collections.addAll() gives an "unchecked generic
// array creation ... for varargs parameter" warning.
partFactories.add(new FuelFilter.Factory());
// ...
}
private static Random rand = new Random(47);
public static Part createRandom() {
int n = rand.nextInt(partFactories.size());
return partFactories.get(n).create();
}
}
class Filter extends Part {}
class FuelFilter extends Filter {
// Create a Class Factory for each specific type:
public static class Factory
implements typeinfo.factory.Factory<FuelFilter> {
public FuelFilter create() { return new FuelFilter(); }
}
}
Class.getMethods()
// Proxy Pattern
class RealObject implements Interface {
public void doSomething() { print("doSomething"); }
public void somethingElse(String arg) {
print("somethingElse " + arg);
}
}
class SimpleProxy implements Interface {
private Interface proxied;
public SimpleProxy(Interface proxied) {
this.proxied = proxied;
}
public void doSomething() {
print("SimpleProxy doSomething");
proxied.doSomething();
}
public void somethingElse(String arg) {
print("SimpleProxy somethingElse " + arg);
proxied.somethingElse(arg);
}
}
class SimpleProxyDemo {
public static void consumer(Interface iface) {
iface.doSomething();
iface.somethingElse("bonobo");
}
public static void main(String[] args) {
consumer(new RealObject());
consumer(new SimpleProxy(new RealObject()));
}
}
class DynamicProxyHandler implements InvocationHandler {
private Object proxied;
public DynamicProxyHandler(Object proxied) {
this.proxied = proxied;
}
public Object
invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("**** proxy: " + proxy.getClass() +
", method: " + method + ", args: " + args);
if(args != null)
for(Object arg : args)
System.out.println(" " + arg);
return method.invoke(proxied, args);
}
}
class SimpleDynamicProxy {
public static void consumer(Interface iface) {
iface.doSomething();
iface.somethingElse("bonobo");
}
public static void main(String[] args) {
RealObject real = new RealObject();
consumer(real);
// Insert a proxy and call again:
Interface proxy = (Interface)Proxy.newProxyInstance(
Interface.class.getClassLoader(),
new Class[]{ Interface.class },
new DynamicProxyHandler(real));
consumer(proxy);
}
}
public interface Null {}
class Person {
public final String first;
public final String last;
public final String address;
// etc.
public Person(String first, String last, String address){
this.first = first;
this.last = last;
this.address = address;
}
public String toString() {
return "Person: " + first + " " + last + " " + address;
}
public static class NullPerson
extends Person implements Null {
private NullPerson() { super("None", "None", "None"); }
public String toString() { return "NullPerson"; }
}
public static final Person NULL = new NullPerson();
}
A Stub
is a sophisticated object that does lots of things.
You usually create lots of small, simple Mock Objects
if you need to do many things.
It’s possible to reach in and call all of the methods using reflection, even private methods.
static void callHiddenMethod(Object a, String methodName)
throws Exception {
Method g = a.getClass().getDeclaredMethod(methodName);
g.setAccessible(true);
g.invoke(a);
}
You may think that you can prevent this by only distributing compiled code, but that’s no
solution.
All you must do is run javap
, which is the decompiler that comes with the JDK. javap -private Class
The intent of OOP is to use polymorphic method calls everywhere you can, and RTTI only when you must.
clearSpitValve()
method in the base class Instrument
, but this is confusing because it implies that Percussion
, Stringed
and Electronic
instruments also have spit valves.Wind
, in this case). preparelnstrument()
method in the base class. Some types of problems, such as gui, simulation, are difficult to solve without support for concurrency.
Executors
are the preferred method for starting tasks in Java SE5/6.
Runnable
ExecutorService.execute()
// A CachedThreadPool will generally create as many threads as it needs,
// then will stop creating new threads as it recycles the old ones,
// so it’s a reasonable first choice as an Executor.
Executors.newCachedThreadPool()
// You limit the number of threads.
Executors.newFixedThreadPool()
// A SingleThreadExecutor is like a FixedThreadPool with a size of one thread.
Executors.newSingleThreadExecutor()
Callable
Future<> = ExecutorService.submit()
The overloaded Executors.callable()
method takes a Runnable
and produces a
Callable
.
ExecutorService
has some invoke methods
that run collections of Callable
objects.
// Old-style:
// Thread.sleep(100);
// Java SE5/6-style:
TimeUnit.MILLISECONDS.sleep(100);
yield()
and sleep()
allows the thread scheduler to switch to another thread.
Thread.currentThread().setPriority(priority)
MAX_PRIORITY
, NORM_PRIORITY
, and MIN_PRIORITY
when you’re adjusting priority levels. yeild()
give a hint to the threadscheduling mechanism that you’ve done enough and that some other task might as well have the CPU.
public class DaemonThreadFactory implements ThreadFactory {
public Thread newThread(Runnable r) {
Thread t = new Thread(r);
t.setDaemon(true);
return t;
}
}
ExecutorService exec = Executors.newCachedThreadPool(
new DaemonThreadFactory());
for(int i = 0; i < 10; i++)
exec.execute(new DaemonFromFactory());
The Daemon thread is set to daemon mode and it then spawns a bunch of other threads—which
are implicitly set to daemon mode.
To clarify these discussions, I shall attempt to use the term "task" when I am describing the work that is being done, and "thread" only when I am referring to the specific mechanism that’s driving the task.
omitted