Thinking in Java from Chapter 7
From Thinking in Java 4th Edition
final
1. 对于基本类型,final使数值恒定不变
2. 对于对象引用,final使引用恒定不变,即不能指向别的对象,但指向的对象本身可以改变(The same for array in Java)
import java.util.*;
import static net.mindview.util.Print.*; class Value{
int i; // Package access
public Value(int i){this.i = i;}
} public class FinalData{
private static Random rand = new Random(47);
private String id; public FinalData(String id){this.id = id;} // Can be compile-time constants;
private final int valueOne = 9;
private static final int valueTwo = 99; // Typical public constant:
public static final int VALUE_THREE = 99; // Cannot be compile-time constants:
private final int i4 = rand.nextInt(20);
static final int INT_5 = rand.nextInt(20);
private Value v1 = new Value(11);
private final Value v2 = new Value(22);
private static final Value VAL_3 = new Value(33); // Arrays:
private final int[] a = {1, 2, 3, 4, 5, 6};
public String toString(){
return id + ": " + "i4 = " + i4 + ", INT_5" + INT_5;
} public static void main(String[] args){
FinalData fd1 = new FinalData("fd1");
//! fd1.valueOne++; // Error: can't change value
fd1.v2.i++; // Object isn't constant!
fd1.v1 = new Value(9); // OK -- not final for(int i = 0; i < f1.a.length; ++i)
++fd1.a[i]; // Object isn't constant! //! fd1.v2 = new Value(0); // Error: can't
//! fd1.VAL_3 = new Value(1); // change reference
//! fd1.a = new int[3]; print(fd1);
print("Creating new FinalData");
FinalData fd2 = new FinalData("fd2");
print(fd1);
print(fd2);
}
} /* Output:
fd1: i4 = 15, INT_5 = 18
Creating new FinalData
fd1: i4 = 15, INT_5 = 18
fd2: i4 = 13, INT_5 = 18
*/
Blank final
一个类中的final域可以做到根据对象有所不同,却又保持不变
class Poppet{
private int i;
Poppet(int ii) {i = ii;}
}
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
}
public BlankFinal(int x){
j = x; // Initialize blank final
p = new Poppet(x); // Initialize blank final reference
}
public static void main(String[] args){
new BlankFinal();
new BlankFinal(47);
}
}
final方法
1. 锁定该方法,防止任何继承类修改它的含义
2. 效率
类中的所有private方法都被隐式地指定为final。
了解包括继承在内的初始化全过程:
import static net.mindview.util.Print.*;
class Insect{
private int i = 9;
protected int j;
Insect(){
print("i = " + i + ", j = " + j);
j = 39;
}
private static int x1 = printInit("static Insect.x1 initialized");
static int printInit(String s){
print(s);
return 47;
}
}
public class Beetle extends Insect{
private int k = printInit("Beetle.k initialized");
public Beetle(){
print("k = " + k);
print("j = " + j);
}
private static int x2 = printInit("static Beetle.x2 initialized");
public static void main(String[] args){
print("Beetle constructor");
Beetle b = new Beetle();
}
} /* Output:
static Insect.x1 initialized
static Beetle.x2 initialized
Beetle constructor
i = 9, j = 0
Beetle.k initialized
k = 47
j = 39
*/
继承
Note类
//: polymorphism/music/Note.java
package polymorphism.music; public enum Note{
MIDDLE_C, C_SHARP, B_FLAT; // Etc.
}
Instrument类
//: polymorphism/music/Instrument.java
package polymorphism.music;
import static net.mindview.util.Print.*; class Instrument{
public void play(Note n){
print("Instrument.play()");
}
}
Wind类
// Wind objects are instruments
// because they have the same interface:
public class Wind extends Instrument{
// Redefine interface method
public void play(Note n){
print("Wind.play() " + n);
}
}
Music类
package polymorphism.music;
public class Music{
public static void tune(Instrument i){
// ...
i.play(Note.MIDDLE_C);
}
public static void main(String[] args){
Wind flute = new Wind();
tune(flute); // Upcasting
}
} /* Output:
Wind.play() MIDDLE_C
*/
Stringed和Brass类
package polymorphism.music;
import static net.mindview.util.Print.*; class Stringed extends Instrument{
public void play(Note n){
print("Stringed.play() " + n);
}
} class Brass extends Instrument{
public void play(Note n){
print("Brass.play() " + n);
}
}
讲一个方法调用和一个方法主体关联在一起,被称作绑定。
1. 前期绑定:程序执行前进行绑定。
2. 后期绑定(也叫动态绑定):在运行时根据对象的类型进行绑定。
Java中除了static方法和final方法(private方法属于final方法)之外,其它所有方法都是后期绑定。Java正是通过动态绑定来实现多态。
缺陷:“覆盖”私有方法
package polymorphism;
import static net.mindview.util.Print.*; public class PrivateOverride{
private void f(){ print("private f()");} public static void main(String[] args){
PrivateOverride po = Derived();
}
} class Derived extends PrivateOverride{
public void f() { print("public f()");}
} /* Output:
private f()
*/
只有普通的方法调用可以是多态的。如果直接访问某个域,这个访问就将在编译期间进行解析:
class Super{
public int field = 0;
public int getField(){ return field;}
}
class Sub extends Super{
public int field = 1;
public int getField() { return field;}
public int getSuperField() { return super.field;}
}
public class FiedlAccess{
public static void main(String[] args){
Super sup = new Sub(); // Upcasting
System.out.println("sup.field = " + sup.field + ", sup.getField() = " + sup.getField());
Sub sub = new Sub();
System.out.println("sub.field = " + sub.field + ", sub.getField" + sub.getField() + ", sub.getSuperField = " + sub.getSuperField());
}
} /* Output:
sup.field = 0, sup.getField() = 1
sub.field = 1, sub.getField() = 1, sub.getSuperField = 0
*/
如果方法是静态的,它的行为也不是多态的
class StaticSuper{
public static String staticGet(){
return "Base staticGet()";
}
public String dynamicGet(){
return "Base dynamicGet()";
}
}
class StaticSub extends StaticSuper {
public static String staticGet(){
return "Derived staticGet()";
}
public String dynamicGet(){
return "Derived dynamicGet()";
}
}
public class StaticPolymorphism {
public static void main(String[] args){
StaticSuper sup = new StaticSub(); // Upcasting
System.out.println(sup.staticGet());
System.out.println(sup.dynamicGet());
}
} /* Output:
Base staticGet()
Derived dynamicGet()
*/
构造器并不具有多态性,它们实际是static方法,只不过该static声明是隐式的。基类构造器总是在导出类的构造过程中被调用,而且按照继承层次逐渐向上链接,以使每个基类构造器得到调用。
package polymorphism;
import static net.mindview.util.Print.*; class Meal{
Meal(){ print("Meal()");}
} class Bread{
Bread(){ print("Bread()");}
} class Cheese{
Cheese(){ print("Cheese()");}
} class Lettuce{
Lettuce(){ print("Lettuce()");}
} class Lunch extends Meal{
Lunch(){ print("Lunch()");}
} class PortableLunch extends Lunch{
PortableLunch() { print("PortableLunch()");}
} public class Sandwich extends PortableLunch{
private Bread b = new Bread();
private Cheese c = new Cheese();
private Lettuce l = new Lettuce(); public Sandwich(){ print("Sandwich()");} public static void main(String[] args){
new Sandwich();
}
} /* Output:
Meal()
Lunch()
PortableLunch()
Sandwich()
*/
Java运行顺序:
1. 加载类,如有基类,加载相应的基类
2. 从根基类开始做static初始化,然后是下一个导出类的static的初始化
3. 完成加载后,进行对象的创建。
4. 调用基类构造器。(基类成员如果是基本类型,则被设为默认值;基类成员如果是对象引用,则被设置为null)
5. 然后是导出类的构造器。
(每个类的编译代码都存在于自己的独立的文件中。该文件只在需要使用程序代码时才会被加载。可以说:类的代码在初次使用时才被加载。)
继承与类清理
package polymorphism;
import static net.mindview.util.Print.*; class Characteristic{
private String s; Characteristic(String s){
this.s = s;
print("Creating Characteristic " + s);
} protected void dispose(){
print("disposing Characteristic " + s);
}
} class Description{
private String s; Description(String s){
this.s = s;
print("Creating Description " + s);
} protected void dispose(){
print("disposing Description " + s);
}
} class LivingCreature{
private Characteristic p = new Characteristic("is alive");
private Description t = new Description("Basic Living Creature"); LivingCreature(){
print("LivingCreature()");
} protected void dispose(){
print("LivingCreature dispose");
t.dispose();
p.dispose();
}
} class Animal extends LivingCreature {
private Characteristic p = new Characteristic("has heart");
private Description t = new Description("Animal not Vegetable"); Animal(){ print("Animal()");} protected void dispose(){
print("Animal dispose");
t.dispose();
p.dispose();
super.dispose();
}
} class Amphibian extends Animal {
private Characteristic p = new Characteristic("Can live in water");
private Description t = new Description("Both water and land"); Amphibian(){
print("Amphibian()");
} protected void dispose(){
print("Amphibian dispose");
t.dispose();
p.dispose();
super.dispose();
}
} public class Frog extends Amphibian {
private Characteristic p = new Characteristic("Croak");
private Description t = new Description("Eats Bugs"); public Frog() { print("Frog()");} protected void dispose(){
print("Frog dispose");
t.dispose();
p.dispose();
super.dispose();
} public static void main(String[] args){
Frog frog = new Frog();
print("Bye!");
frog.dispose();
}
} /* Output:
Creating Characteristic is alive
Creating Description Basic Living Creature
LivingCreature()
Creating Characteristic has heart
Creating Description Animal not Vegetable
Animal()
Creating Characteristic Can live in water
Creating Description Both water and land
Amphibian()
Creating Characteristic Croak
Creating Description Eats Bugs
Frog()
Bye!
Frog dispose
disposing Description Eats Bugs
disposing Characteristic Croak
Amphibian dispose
disposing Description Both water and land
disposing Characteristic Can live in water
...
*/
共享对象
import static net.mindview.util.Print.*;
class Shared {
private int refcount = 0;
private static long counter = 0;
private final long id = counter++;
public Shared(){
print("Creating " + this);
}
public void addRef(){ ++refcount; }
protected void dispose(){
if(0 == --refcount){
print("Disposing " + this);
}
}
public String toString() { return "Shared " + id; }
}
class Composing {
private Shared shared;
private static long counter = 0;
private final long id = counter++;
public Composing(Shared shared) {
print("Creating " + this);
this.shared = shared;
this.shared.addRef();
}
public void dispose(){
print("disposing " + this);
shared.dispose();
}
public String toString(){ return "Composing " + id;}
}
public class ReferenceCounting {
public static void main(String[] args){
Shared shared = new Shared();
Composing[] composing = {new Composing(shared),
new Composing(shared), new Composing(shared),
new Composing(shared), new Composing(shared)};
for(Composing c : composing)
c.dispose();
}
} /* Output:
Creating Shared 0
Creating Composing 0
Creating Composing 1
Creating Composing 2
Creating Composing 3
Creating Composing 4
disposing Composing 0
disposing Composing 1
disposing Composing 2
disposing Composing 3
disposing Composing 4
disposing Shared 0
*/
构造器内部的多态行为:
import static net.mindview.util.Print.*;
class Glyph {
void draw() { print("Glyph.draw()");}
Glyph(){
print("Glyph() before draw()");
draw();
print("Glyph() after draw()");
}
}
class RoundGlyph extends Glyph{
private int radius = 1;
RoundGlyph(int r){
radius = r;
print("RoundGlyph.RoundGlyph(), radius = " + radius);
}
void draw(){
print("RoundGlyph.draw(), radius = " + radius);
}
}
public class PolyConstructors{
public static void main(String[] args){
new RoundGlyph(5);
}
} /* Output:
Glyph() before draw()
RoundGlyph.RoundGlyph(), radius = 0
Glyph() after draw()
RoundGlyph.RoundGlyph(), radius = 5
*/
用继承设计
import static net.mindview.util.Print.*;
class Actor {
public void act(){}
}
class HappyActor extends Actor {
public void act() { print("HappyActor");}
}
class SadActor extends Actor {
public void act() { print("SadActor");}
}
class Stage {
private Actor actor = new HappyActor();
public void change() { actor = new SadActor();}
public void performPlay() { actor.act();}
}
public class Transmogrify {
public static void main(String[] args){
Stage stage = new Stage();
stage.performPlay();
stage.change();
stage.performPlay();
}
} /* Output:
HappyActor
SadActor
*/
设计准则:用继承表达行为的差异,用组合表达状态上的变化。
向下转型与运行时类型识别(RTTI)
class Useful{
public void f() {}
public void g() {}
}
class MoreUseful extends Useful {
public void f() {}
public void g() {}
public void w() {}
public void v() {}
public void u() {}
}
public class RTTI {
public static void main(String[] args){
Useful[] x = {
new Useful(),
new MoreUseful() // Upcast
};
x[0].f();
x[1].g();
// Compile time: method not found in Useful:
//! x[1].u();
((MoreUseful)x[1]).u(); // Downcast/RTTI
((MoreUseful)x[0]).u(); // Exception thrown
}
}
抽象类
包含抽象方法的类叫抽象类。所以为了使某个类成为抽象类,仅需将某些方法声明为抽象类即可。
如果从一个抽象类继承,并想创建该新类的对象,那么就必须为基类中的所有抽象方法提供方法定义。如果不这样做(可以选择不做),那么导出类便也是抽象类,且编译器将会强制我们用abstract关键字来限定这个类。
interface这个关键字产生了一个完全抽象的类,它根本就没有提供任何具体的实现。它允许创建:
1. 方法名
2. 参数列表
3. 返回类型
但没有任何方法体。
package interfaces.music4;
import polymorphism.music.Note;
import static net.mindview.util.Print.*; abstract class Instrument {
private int i; // Storage allocated for each
public abstract void play(Note n);
public String what() { return "Instrument";}
public abstract void adjust();
} class Wind extends Instrument {
public void play(Note n){
print("Wind.play() " + n);
} public String what() { return "Wind";}
public void adjust() {}
}
接口被用来建立类与类之间的协议。
接口也可以包含域,但是这些域隐式地被指定为static和final的
package interfaces.music5;
import polymorphism.music.Note;
import static net.mindview.util.Print.*; interface Instrument {
// 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){
print(this + ".play() " + n);
} public String toString() {return "Wind";}
public void adjust() {print(this + ".adjust()");}
} class Percussion implements Instrument {
public void play(Note n){
print(this + ".play() " + n);
} public String toString() {return "Percussion";}
public void adjust() {print(this + ".adjust()");}
}
完全解耦
package interfaces.classprocessor;
import java.util.*;
import static net.mindview.util.Print.*; class Processor {
public String name() {
return getClass().getSimpleName();
} Object process(Object input) { return input;}
} class Upcase extends Processor {
String process(Object input) {
// Covariant return
return ((String)input).toUpperCase();
}
} class Downcase extends Processor {
String process(Object input){
return ((String)input).toLowerCase();
}
} class Splitter extends Processor {
String process(Object input) {
// The split() argument divides a string into pieces:
return Arrays.toString(((String)input).split(" "));
}
} public class Apply {
public static void process(Processor p, Object s){
print("Using Processor " + p.name());
print(p.process(s));
} public static String s = "Disagreement with beliefs is by definition incorrect"; public static void main(String[] args){
process(new Upcase(), s);
process(new Downcase(), s);
process(new Splitter(), s);
}
} /* Output:
Using Processor Upcase
DISAGREEMENT WITH BELIEFS IS BY DEFINITION INCORRECT
Using Processor Downcase
disagreement with beliefs is by definition incorrect
Using Processor Splitter
[Disagreement, with, beliefs, is, by, definition, incorrect]
*/
接口可复用结构
Processor接口
//: interfaces/interfaceprocessor/Processor.java
package interfaces.interfaceprocessor; public interface Processor {
String name();
Object process(Object input);
}
Apply类
//: interfaces/interfaceprocessor/Apply.java
package interfaces.interfaceprocessor;
import static net.mindview.util.Print.*; public class Apply {
public static void process(Processor p, Object s){
print("Using Processor " + p.name());
print(p.process(s));
}
}
复用代码第一种方式,客户端程序员遵循接口编写自己的类
package interfaces.interfaceprocessor;
import java.util.*; public abstract class StringProcessor implements Processor {
public String name() {
return getClass().getSimpleName();
} public abstract String process(Object input); public static String s = "If she weights the same as a duck, she's made of wood"; public static void main(String[] args){
Apply.process(new Upcase(), s);
Apply.process(new Downcase(), s);
Apply.process(new Splitter(), s);
}
} class Upcase extends StringProcessor {
public String process(Object input) {
// Covariant return
return ((String)input).toUpperCase();
}
} class Downcase extends StringProcessor {
public String process(Object input) {
return ((String)input).toLowerCase();
}
}
适配器模式:适配器中的代码将接受你所拥有的接口,并产生你所需要的接口。
package interfaces.interfaceprocessor;
import java.util.*; public abstract class StringProcessor implements Processor {
public String name() {
return getClass().getSimpleName();
} public abstract String process(Object input); public static String s = "If she weights the same as a duck, she's made of wood"; public static void main(String[] args){
Apply.process(new Upcase(), s);
Apply.process(new Downcase(), s);
Apply.process(new Splitter(), s);
}
} class Upcase extends StringProcessor {
public String process(Object input) {
// Covariant return
return ((String)input).toUpperCase();
}
} class Downcase extends StringProcessor {
public String process(Object input) {
return ((String)input).toLowerCase();
}
} package interfaces.interfaceprocessor;
import interfaces.filters.*; 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);
}
} public class FilterProcessor {
public static void main(String[] args) {
Waveform w = new Waveform();
Apply.process(new FilterAdapter(new LowPass(1,0)), w);
Apply.process(new FilterAdapter(new HighPass(2.0)), w);
Apply.process(
new FilterAdapter(new BandPass(3.0, 4.0)), w);
}
}
具体类组合数个接口之后产生了一个新类:
interface CanFight {
void fight();
}
interface CanSwim {
void swim();
}
interface CanFly {
void fly();
}
class ActionCharacter {
public void fight(){}
}
class Hero extends ActionCharacter implements CanFight, CanSwim, CanFly {
public void swim() {}
public void fly() {}
}
public class Adventure {
public static void t(CanFight x) { x.fight();}
public static void u(CanSwim x) { x.swim();}
public static void v(CanFly x) { x.fly();}
public static void w(ActionCharacter x) { x.fight();}
public static void main(String[] args){
Hero h = new Hero();
t(h); // Treat it as a CanFight
u(h); // Treat it as a CanSwim
v(h); // Treat it as a CanFly
w(h); // Treat it as an ActionCharacter
}
}
这个例子展示了使用接口的核心原因:为了能够向上转型为多个基类型(以及由此而带来的灵活性)。
使用接口的第二个原因与使用抽象类相同:防止客户端程序员创建该类的对象,并确保这仅仅是建立一个接口。
通过继承,可以:
1. 在接口中添加新的方法声明
2. 在新接口中组合数个接口
interface Monster {
void menace();
}
interface DangerousMonster extends Monster {
void destroy();
}
interface Lethal {
void kill();
}
class DragonZilla implements DangerousMonster {
public void menace() {}
public void destroy() {}
}
interface Vampire extends DangerousMonster, Lethal {
void drinkBlood();
}
class VeryBadVampire implements Vampire {
public void menace() {}
public void destroy() {}
public void kill() {}
public void drinkBlood() {}
}
public class HorrorShow {
static void u(Monster b) { b.menace();}
static void v(DangerousMonster d) {
d.menace();
d.destroy();
}
static void w(Lethal l) { l.kill();}
public static void main(String[] args){
DangerousMonster barney = new DragonZilla();
u(barney);
v(barney);
Vampire vlad = new VeryBadVampire();
u(vlad);
v(vlad);
w(vlad);
}
}
接口的常见用法就是策略设计模式,你主要就是要声明:“你可以用任何你想要的对象来调用我的方法,只要你的对象遵循我的接口。”例如,Java中的Scanner类的构造器就是一个Readable接口。如果你创建了一个新类,并想让Scanner可以作用它,那么你就应该让它成为Readable:
import java.nio.*;
import java.util.*; public class RandomWorks implements Readable {
private static Random rand = new Random(47);
private static final char[] capitals = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();
private static final char[] lowers = "abcdefghijklmnopqrstuvwxyz".toCharArray();
private static final char[] vowels = "aeiou".toCharArray(); private int count; public RandomWorks(int count) { this.count = count;} public int read(CharBuffer cb) {
if(count-- = 0)
return -1; // Indicates end of input
cb.append(capitals[rand.nextInt(capitals.length)]);
for(int i = 0; i < 4; ++i){
cb.append(vowels[rand.nextInt(vowels.length)]);
cb.append(vowels[rand.nextInt(vowels.length)]);
}
cb.append(" ");
return 10; // Number of characters appended
} public static void main(String[] args){
Scanner s = new Scanner(new RandomWorks(10));
while(s.hasNext())
System.out.println(s.next());
}
}
假设还有一个没有实现Readable的类,怎样才能让Scanner作用于它呢?
import java.util.*;
public class RandomDoubles {
private static Random rand = new Random(47);
public double next() { return rand.nextDouble();}
public static void main(String[] args){
RandomDoubles rd = new RandomDoubles();
for(int i = 0; i < 7; ++i)
System.out.println(rd.next() + " ");
}
}
我们需要再次使用适配器。但在本例中,被适配的类可以通过继承和实现Readable接口来创建。通过使用interface关键字提供的伪多重继承,可以生成既是RandomDoubles又是Readable的新类:
import java.nio.*;
import java.util.*; public class AdaptedRandomDoubles extends RandomDoubles implements Readable {
private int count;
public AdaptedRandomDoubles(int count) {
this.count = count;
} public int read(CharBuffer cb) {
if(count-- == 0)
return -1;
String result = Double.toString(next()) + " ";
cb.append(result);
return result.length();
} public static void main(String[] args){
Scanner s = new Scanner(new AdaptedRandomDoubles(7)); while(s.hasNextDouble())
System.out.println(s.nextDouble() + " ");
}
}
在这个方法中,我们可以在任何现有类之上添加新的接口,所以这意味着让方法接受接口类型,是一种让任何类都可以对该方法进行适配的方式。这就是使用接口而不是类的强大之处。
工厂方法设计模式。与直接调用构造器不同,我们在工厂对象上调用的是创建方法,而该工厂对象将生成接口的某个实现的对象。
import static net.mindview.util.Print.*;
interface Service {
void method1();
void method2();
}
interface ServiceFactory {
Service getService();
}
class Implementation1 implements Service {
Implementation1() {} // Package access
public void method1() {print("Implementation1 method1");}
public void method2() {print("Implementation2 method2");}
}
class Implementation1Factory implements ServiceFactory {
public Service getService() {
return new Implementation1();
}
}
class Implementation2 implements Service {
Implementation2() {} // Package access
public void method1() {print("Implementation2 method1");}
public void method2() {print("Implementation2 method2");}
}
class Implementation2Factory implements ServiceFactory {
public Service getService(){
return new Implementation2();
}
}
public class Factories {
public static void serviceConsumer(ServiceFactory fact){
Service s = fact.getService();
s.method1();
s.method2();
}
public static void main(String[] args){
serviceConsumer(new Implementation1Factory());
// Implementations are completely interchangeable:
serviceConsumer(new Implementation2Factory());
}
} /* Output:
Implementation1 method1
Implementation1 method2
Implementation2 method1
Implementation2 method2
*/
Thinking in Java from Chapter 7的更多相关文章
- Thinking in Java from Chapter 15
From Thinking in Java 4th Edition. 泛型实现了:参数化类型的概念,使代码可以应用于多种类型.“泛型”这个术语的意思是:“适用于许多许多的类型”. 如果你了解其他语言( ...
- Thinking in Java from Chapter 11
From Thinking in Java 4th Edition 持有对象 // Simple container example (produces compiler warnings.) // ...
- Thinking in Java from Chapter 21
From Thinking in Java 4th Edition 并发 线程可以驱动任务,因此你需要一种描述任务的方式,这可由Runnable接口来提供. 要想定义任务,只需要实现Runnable接 ...
- Thinking in Java from Chapter 10
From Thinking in Java 4th Edition 内部类 public class Parcel1 { class Contents { private int i = 11; pu ...
- akka---Getting Started Tutorial (Java): First Chapter
原文地址:http://doc.akka.io/docs/akka/2.0.2/intro/getting-started-first-java.html Introduction Welcome t ...
- java1234教程系列笔记 S1 Java SE chapter 02 写乘法口诀表
一.水仙花数 1.方式一:这是我的思路,取各个位数的方式.我个人习惯于使用取模运算. public static List<Integer> dealNarcissiticNumberMe ...
- java1234教程系列笔记 S1 Java SE chapter 02 lesson 03 java基本数据类型
第二章 第三节 数据类型 3.1 分类 基本数据类型.引用类型 3.2整型 byte 8 short 16 int 32 long 64 作业: A:1-10求和 B:float double 的最 ...
- Eclipse中使用Gradle构建Java Web项目
Gradle是一种自动化建构工具,使用DSL来声明项目设置.通过Gradle,可以对项目的依赖进行配置,并且自动下载所依赖的文件,使得构建项目的效率大大提高. 1. 安装Gradle 下载Gradle ...
- 【转】O'Reilly Java系列书籍建议阅读顺序(转自蔡学庸)
Learning Java the O'Reilly's Way (Part I) Java 技术可以说是越来越重要了,不但可以用在计算机上,甚至连电视等家电用品,行动电话.个人数字助理(PDA)等电 ...
随机推荐
- django-celery使用
1.新进一个django项目 - proj/ - proj/__init__.py - proj/settings.py - proj/urls.py - manage.py 2.在该项目创建一个pr ...
- Python 高阶函数map(),filter(),reduce()
map()函数,接收两个参数,一个是函数,一个是序列,map()把传入的函数依次作用于序列的每个元素,并把结果作为新的序列返回: aa = [1, 2, 3, 4, 5] print("ma ...
- 如何学习DeepLearning
多年来,科学家们为了搞清楚神经网络的运行机制,进行了无数次实验.但关于神经网络的内在运行方式,目前还没有系统性的理论,没有具体的路线可以指引你获得更好的性能.简单地下载开源工具包直接使用并不能跑出很棒 ...
- Sql Server数据库之identity(自增)
一.identity的基本用法 1.identity的含义: identity表示该字段的值会自动更新,通常情况下,不允许直接修改identity修饰的字段,否则编译会报错 2.基本语法 列名 数据 ...
- Ansible运维工具
1.Ansible是一款极为灵活的开源工具套件,能够大大简化Unix管理员的自动化配置管理与流程控制方式.可以通过命令行或者GUI来使用Ansible,运行Ansible的服务器这里俗称“管理节点”: ...
- jQuery——检测滚动条是否到达底部
一.jQuery检测浏览器window滚动条到达底部 jQuery获取位置和尺寸相关函数:$(document).height() 获取整个页面的高度:$(window).height() ...
- JS游戏控制时间代码
var canvas = new HGAME.canvas();var testBox=document.getElementById('boxRender');testBox.appendChild ...
- php的AES加密、解密类
<?php /** * php.ios.Android 通用的AES加密.解密方法 */ namespace Common\Business; class AESCrypt { /** * 初始 ...
- 牛客小白月赛12 J 月月查华华的手机(序列自动机)
---恢复内容开始--- 题目来源:https://ac.nowcoder.com/acm/contest/392/J 题意: 题目描述 月月和华华一起去吃饭了.期间华华有事出去了一会儿,没有带手机. ...
- node.js中实现http服务器与浏览器之间的内容缓存
一.缓存的作用 1.减少了数据传输,节约流量. 2.减少服务器压力,提高服务器性能. 3.加快客户端加载页面的速度. 二.缓存的分类 1.强制缓存,如果缓存有效,则不需要与服务器发生交互,直接使用缓存 ...