1 java工作方式
源代码->编译器->输出字节码文件->java虚拟机
2.每个Java程序最少会有一个类以及一个main()。每个应用程序只有一个main()
3.java中integer与boolean两种类型不相容
4.对象本身已知的事物称为实例变量,他们代表对象的状态。
6.所有带小数点的值都会被java当做double处理
7.变量命名方法
名称必须以字母,下划线,或钱符号开头,不能用数字
不能用Java关键字
8.只有引用到对象的变量,对于同一个java虚拟机来说,所有引用变量大小相同
9.数组也是对象,当数组中有引用类型时,数组每个元素都要实例化
10.任意类的每个实例带有相同的方法,但是方法可以根据实例变量的值来表
现不同的行为
11实例变量是方法以外,类中的变量,实例变量有默认值,局部变量无默认值,所以局部变量使用前一定要初始化。
12变量的比较,引用数据类型不能使用“==”,否则,只有相同的引用才会返回true
13.foreach
for(类型名 循环元素名:要循环的数组或集合)
封装基本原则:将实例变量定义为私有,并提供共有的Setter与Getter来改变或得到实例变量。并且Setter能保证数据的合理性
继承子类会继承父类所有public类型的实例变量和方法,继承下来的方法可以覆盖掉,但实例变量不能覆盖掉。调用子类对象的这个方法时会调用覆盖过的版本。如果在子类的对象的方法中还需调用被覆盖过的父类方法,则需使用super关键字。
方法覆盖的原则
1.重写的方法参数必须要一样,且返回值类型必须要兼容。即不论父类使用了哪种参数,覆盖此方法的子类一定要使用相同的参数;不论父类声明的返回类型是什么,子类必须要声明返回一样的类型或该类型的子类。
2.不能降低方法的存取权限。这代表存取权必须相同,或者更为开放。举例来说,你不能覆盖掉一个公有的方法并将它标记为私有。目前我们只看到过public与private两种权限,除此之外还有protected与default权限
类的访问权限
类不可以是私有的,也不可以是protected的,如果不希望他人拥有该类的的访问权限,可以把构造器指定为private。
class Soup1 {
private Soup1() {}
// (1) Allow creation via static method:
public static Soup1 makeSoup() {
return new Soup1();
}
}
//
class Soup2 {
private Soup2() {}
// (2) Create a static object and return a reference
// upon request.(The "Singleton" pattern):
private static Soup2 ps1 = new Soup2();
public static Soup2 access() {
return ps1;//静态方法
}
public void f() {}
}
//
// Only one public class allowed per file:
public class Lunch {
void testPrivate() {
// Can't do this! Private constructor:
//! Soup1 soup = new Soup1();
}
void testStatic() {
Soup1 soup = Soup1.makeSoup();
}
void testSingleton() {
Soup2.access().f();
}
} ///:~
用final修饰符修饰的类,表示它是不能被继承,即它不能有子类。如果用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
*///:~
当编译器注意到Betlle还有一个基类,于是他继续进行加载。如果该基类还有自身的基类,那么第二个基类也会被加载。
抽象类与抽象方法
用关键字abstract修饰的类称为abstract类,方法称为abstract方法,抽象方法只有声明,没有实现。
抽象方法只能存在于抽象类与接口中,且抽象类不能使用new关键字创建对象,也不允许使用final和abstract同时修饰一个方法。
如果一个非抽象类继承了抽象类,则必须重写父类的所有抽象方法。
多态
当我们使用父类声明引用变量,使用子类实例化时,如Animal myDog = new Dog();,通过父类的引用变量调用方法时,实际调用的是具体子类覆盖的方法,即一个Animal类型的变量会在不同场合下表现为不同的行为,这种特征叫多态。
方法调用绑定
将一个方法调用同一个方法主体关联起来被称作绑定。若程序前期进行绑定,叫做前期绑定。
在运行时根据对象类型进行绑定,叫做动态绑定或运行绑定。java中除static和final方法之外,其他所有方法都是后期绑定
域与静态方法
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;
}
}
class Sub2 extends Sub{
public int field=2;
public int getField() {
return field;
}
public int getSuperField() {
return super.field;
}
}
public class FieldAccess {
public static void main(String[] args) {
Super sup=new Sub();//upcast
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());
}
}
class StaticSuper{
public static String staticGet() {
return "Base staticGet";
}
public String dynaGet() {
return "dyna dynaget";
}
}
class StaticSub extends StaticSuper{
public static String staticGet() {
return "Derived staticGet()";
}
public String dynaGet() {
return "dyna dynaGet";
}
}
public class StaticTest {
public static void main(String[] args) {
StaticSuper sup=new StaticSub();
System.out.println(sup.staticGet());//不可多态
System.out.println(sup.dynaGet());
}
}
构造器的多态
调用构造顺序
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()
Bread()
Cheese()
Lettuce()
Sandwich()
*///:~
补充
class Glyph {
void draw() { System.out.println("Glyph.draw()"); }
Glyph() {
System.out.println("Glyph() before draw()");
draw();//在子类构造器调用之前调用
System.out.println("Glyph() after draw()");
}
}
//
class RoundGlyph extends Glyph {
private int radius = 1;
RoundGlyph(int r) {
radius = r;
System.out.println("RoundGlyph.RoundGlyph(), radius = " + radius);
}
void draw() {
System.out.println("RoundGlyph.draw(), radius = " + radius);
}
}
//
public class PolyConstructors {
public static void main(String[] args) {
new RoundGlyph(5);
}
} /* Output:
Glyph() before draw()
RoundGlyph.draw(), radius = 0
Glyph() after draw()
RoundGlyph.RoundGlyph(), radius = 5
*///:~
向下转型
当不能顺利转换,会抛出异常
class Useful{
public void f() {System.out.println("Useful.f");};
public void g() {System.out.println("Useful.g");};
}
class MoreUseful extends Useful{
public void f() {System.out.println("MUseful.f");};
public void g() {System.out.println("MUseful.g");};
public void u() {System.out.println("MUseful.u");};
public void v() {System.out.println("MUseful.v");};
public void w() {System.out.println("MUseful.w");};
}
public class RTTI {
public static void main(String[] args) {
Useful[] x= {new Useful(),new MoreUseful()};
x[0].f();
x[1].g();
((MoreUseful)x[1]).u();
((MoreUseful)x[0]).u();//有异常
}
}
接口
接口中的变量都是public static(可省略)类型的常量,接口中的方法都是public abstract(可省略)方法
接口是完全的抽象类,用interface代替class定义接口类,用implements实现。继承只能单继承,而接口可以有多个,接口的意义在于多态。
接口只能有常量,不能有变量。
接口可分为公有接口和友好接口。
完全解耦
首先Process为普通类
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) {
System.out.println("Using Processor " + p.name());
System.out.println(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]
*///:~
当另外一个相似的类也具有相似的结构,却不能复用Apply.process方法
//另一个类适用Apply.process
public class Waveform {
private static long counter;
//每个类id不变
private final long id = counter++;
public String toString() { return "Waveform " + id; }
} ///:~
//Filter类
public class Filter {
public String name() {
return getClass().getSimpleName();
}
public Waveform process(Waveform input) { return input; }
} ///:~
public class LowPass extends Filter {
double cutoff;
public LowPass(double cutoff) { this.cutoff = cutoff; }
//重载
public Waveform process(Waveform input) {
return input; // Dummy processing
}
} ///:~
public class HighPass extends Filter {
double cutoff;
public HighPass(double cutoff) { this.cutoff = cutoff; }
public Waveform process(Waveform input) { return input; }
} ///:~
public class BandPass extends Filter {
double lowCutoff, highCutoff;
public BandPass(double lowCut, double highCut) {
lowCutoff = lowCut;
highCutoff = highCut;
}
public Waveform process(Waveform input) { return input; }
} ///:~
但当process为一个接口
public interface Processor {
String name();
Object process(Object input);
}
public class Apply {
public static void process(Processor p, Object s) {
System.out.println("Using Processor " + p.name());
System.out.println(p.process(s));
}
} ///:~
import java.util.Arrays;
//
//字符处理
public abstract class StringProcessor implements Processor{
public String name() {
return getClass().getSimpleName();
}
public abstract String process(Object input);
public static String s =
"If she weighs 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();
}
}
//
class Splitter extends StringProcessor {
public String process(Object input) {
return Arrays.toString(((String)input).split(" "));
}
} /* Output:
Using Processor Upcase
IF SHE WEIGHS THE SAME AS A DUCK, SHE'S MADE OF WOOD
Using Processor Downcase
if she weighs the same as a duck, she's made of wood
Using Processor Splitter
[If, she, weighs, the, same, as, a, duck,, she's, made, of, wood]
*///:~
import 多态.Filter;
import 多态.*;
//
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();//调用tostring方法
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);
}
} /* Output:
Using Processor LowPass
Waveform 0
Using Processor HighPass
Waveform 0
Using Processor BandPass
Waveform 0
*///:~
接口也可以继承接口
//moster接口
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);
}
} ///:~
//接口继承才能用extends
使用接口扩充Scnner类
import java.nio.*;
import java.util.*;
//readable接口只有一个方法要实现
public class RandomWords implements Readable {
//控制随机种子
private static Random rand = new Random(47);
private static final char[] capitals =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();//将String类型转换为char[]类型
private static final char[] lowers =
"abcdefghijklmnopqrstuvwxyz".toCharArray();
private static final char[] vowels =
"aeiou".toCharArray();
private int count;
//构造方法
public RandomWords(int count) { this.count = count; }
//实现read方法
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(lowers[rand.nextInt(lowers.length)]);
}
cb.append(" ");
//加了十个字符
return 10; // Number of characters appended
}
public static void main(String[] args) {
Scanner s = new Scanner(new RandomWords(10));
while(s.hasNext())
System.out.println(s.next());
}
} /* Output:
Yazeruyac
Fowenucor
Goeazimom
Raeuuacio
Nuoadesiw
Hageaikux
Ruqicibui
Numasetih
Kuuuuozog
Waqizeyoy
*///:~
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.print(rd.next() + " ");
}
} /* Output:
0.7271157860730044 0.5309454508634242 0.16020656493302599 0.18847866977771732 0.5166020801268457 0.2678662084200585 0.2613610344283964
*///:~
接口适配器
import java.nio.*;
import java.util.*;
//让RandomDoubles适用readable接口
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) {
//可以使用RandomDouble 扩充Scnner类
Scanner s = new Scanner(new AdaptedRandomDoubles(7));
while(s.hasNextDouble())
System.out.print(s.nextDouble() + " ");
}
} /* Output:
0.7271157860730044 0.5309454508634242 0.16020656493302599 0.18847866977771732 0.5166020801268457 0.2678662084200585 0.2613610344283964
*///:~
接口工厂设计模式
interface Service {
void method1();
void method2();
}
//工厂设计模式
interface ServiceFactory {
Service getService();
}
//
class Implementation1 implements Service {
Implementation1() {} // Package access
public void method1() {System.out.println("Implementation1 method1");}
public void method2() {System.out.println("Implementation1 method2");}
}
//
class Implementation1Factory implements ServiceFactory {
public Service getService() {
return new Implementation1();
}
}
//另外一种实现方法
class Implementation2 implements Service {
Implementation2() {} // Package access
public void method1() {System.out.println("Implementation2 method1");}
public void method2() {System.out.println("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
*///:~
Object类
java中所有类都是从Object继承出来的,它是所有类的父类
对象的生存空间
栈:方法调用及变量的生存空间;
堆:对象的生存空间,又称为可垃圾回收的堆。
实例变量存在于所属类中,存在于对象所属堆的空间上,而局部变量和方法的参数都是被声明在方法中,他们是暂时的。调用方法时,会放在调用栈的栈顶。
如果局部变量是对象的引用,只有变量本身会放在栈上,对象本身只会存在堆上。
构造函数
构造函数无返回值且方法名和类名相同
Duck myDuck=newDuck();这其实是在调用Duck的构造函数。唯一能够调用构造函数的方法就是新建一个类,构造函数会在被赋值给引用之前就执行。
如果没写构造函数,编译器会写出默认的构造函数,如果写了构造函数,则编译器不会有默认构造函数。
在创建新对象时,所有继承下来的构造函数都会被执行,即使父类是抽象类也有构造函数,父类的构造函数会在子类创建之前先创建。
补充
this关键字
只能在方法内部使用,表示对调用方法的的那个对象的的引用。
如果在this加了参数列表,那么就有了不同的含义,这将产生对符合此参数列表的某个构造器的明确调用
//: initialization/Flower.java
// Calling constructors with "this"
import static net.mindview.util.Print.*;
//
public class Flower {
int petalCount = 0;
String s = "initial value";
Flower(int petals) {
petalCount = petals;
print("Constructor w/ int arg only, petalCount= "
+ petalCount);
}
Flower(String ss) {
print("Constructor w/ String arg only, s = " + ss);
s = ss;
}
Flower(String s, int petals) {
this(petals);
//! this(s); // Can't call two!
this.s = s; // Another use of "this"
print("String & int args");
}
Flower() {
this("hi", 47);
print("default constructor (no args)");
}
void printPetalCount() {
//! this(11); // Not inside non-constructor!
print("petalCount = " + petalCount + " s = "+ s);
}
public static void main(String[] args) {
Flower x = new Flower();
x.printPetalCount();
}
} /* Output:
Constructor w/ int arg only, petalCount= 47
String & int args
default constructor (no args)
petalCount = 47 s = hi
*///:~
构造器初始化
自动初始化在构造器调用之前执行
public class Counter{
int i;
Counter(){i=7;}
}
所以i先被初始化为0,后变成7.
初始化顺序
在类的内部,变量定义的先后顺序决定了初始化的顺序,即使变量定义散布于方法定义之间,他们仍旧会在任何方法(包括构造器)被调用之前得到初始化。
//: initialization/OrderOfInitialization.java
// Demonstrates initialization order.
import static net.mindview.util.Print.*;
//
// When the constructor is called to create a
// Window object, you'll see a message:
class Window {
Window(int marker) { print("Window(" + marker + ")"); }
}
//
class House {
Window w1 = new Window(1); // Before constructor
House() {
// Show that we're in the constructor:
print("House()");
w3 = new Window(33); // Reinitialize w3
}
Window w2 = new Window(2); // After constructor
void f() { print("f()"); }
Window w3 = new Window(3); // At end
}
//
public class OrderOfInitialization {
public static void main(String[] args) {
House h = new House();
h.f(); // Shows that construction is done
}
} /* Output:
Window(1)
Window(2)
Window(3)
House()
Window(33)
f()
*///:~
静态数据初始化
无论创建多少对象,静态数据只占用一份储存区域。static不能用于局部变量。如果没有初始化,便会获得基本标准初值,如果是一对象的引用,那么它的默认值就是null。
//: initialization/StaticInitialization.java
// Specifying initial values in a class definition.
import static net.mindview.util.Print.*;
//
class Bowl {
Bowl(int marker) {
print("Bowl(" + marker + ")");
}
void f1(int marker) {
print("f1(" + marker + ")");
}
}
//
class Table {
static Bowl bowl1 = new Bowl(1);
Table() {
print("Table()");
bowl2.f1(1);
}
void f2(int marker) {
print("f2(" + marker + ")");
}
static Bowl bowl2 = new Bowl(2);
}
//
class Cupboard {
Bowl bowl3 = new Bowl(3);
static Bowl bowl4 = new Bowl(4);
Cupboard() {
print("Cupboard()");
bowl4.f1(2);
}
void f3(int marker) {
print("f3(" + marker + ")");
}
static Bowl bowl5 = new Bowl(5);
}
//
public class StaticInitialization {
public static void main(String[] args) {
print("Creating new Cupboard() in main");
new Cupboard();
print("Creating new Cupboard() in main");
new Cupboard();
table.f2(1);
cupboard.f3(1);
}
static Table table = new Table();
static Cupboard cupboard = new Cupboard();
} /* Output:
Bowl(1)
Bowl(2)
Table()
f1(1)
Bowl(4)
Bowl(5)
Bowl(3)
Cupboard()
f1(2)
Creating new Cupboard() in main
Bowl(3)
Cupboard()
f1(2)
Creating new Cupboard() in main
Bowl(3)
Cupboard()
f1(2)
f2(1)
f3(1)
*///:~
初始化顺序先是静态对象,而后是“非静态”对象,静态对象只会初始化一次
数组初始化
int a1={1,2,3,4,5};
所有数组都有一个固有成员,length。
可以用花括号括起来初始化对象数组。有两种形式
//: initialization/ArrayInit.java
// Array initialization.
import java.util.*;
//
public class ArrayInit {
public static void main(String[] args) {
Integer[] a = {
new Integer(1),
new Integer(2),
3, // Autoboxing
};
Integer[] b = new Integer[]{
new Integer(1),
new Integer(2),
3, // Autoboxing
};
System.out.println(Arrays.toString(a));
System.out.println(Arrays.toString(b));//输出元素
}
} /* Output:
[1, 2, 3]
[1, 2, 3]
*///:~
可变参数列表
//: initialization/VarArgs.java
// Using array syntax to create variable argument lists.
//
class A {}
//
public class VarArgs {
static void printArray(Object[] args) {//之前表示方法
for(Object obj : args)
System.out.print(obj + " ");
System.out.println();
}
public static void main(String[] args) {
printArray(new Object[]{
new Integer(47), new Float(3.14), new Double(11.11)
});
printArray(new Object[]{"one", "two", "three" });
printArray(new Object[]{new A(), new A(), new A()});
}
} /* Output: (Sample)
47 3.14 11.11
one two three
A@1a46e30 A@3e25a5 A@19821f
*///:~
public class NewVarArgs {
static void printArray(Object... args) {//变化之处
for(Object obj : args)
System.out.print(obj + " ");
System.out.println();
}
public static void main(String[] args) {
// Can take individual elements:
printArray(new Integer(47), new Float(3.14),
new Double(11.11));
printArray(47, 3.14F, 11.11);
printArray("one", "two", "three");
printArray(new A(), new A(), new A());
// Or an array:
printArray((Object[])new Integer[]{ 1, 2, 3, 4 });
printArray(); // Empty list is OK
}
} /* Output: (75% match)
47 3.14 11.11
47 3.14 11.11
one two three
A@1bab50a A@c3c749 A@150bd4d
1 2 3 4
*///:~
有了可变参数,就再也不用显式地编写数组语法了,当你指定参数时,编译器实际上会为你去填充数组。仍可以得到一个数组