1.
package test;
class Soap {
private String s;
Soap() {
System.out.println("Soap()");
s = "Constructed";
}
public String toString() { return s; }
}
public class Test {
private String // Initializing at point of definition:
s1 = "Happy",
s2 = "Happy",
s3, s4;
private Soap castille;
private int i;
private float toy;
// 构造器初始化
public Test() {
System.out.println("Inside Test()");
s3 = "Joy";
toy = 3.14f;
castille = new Soap();
}
// Instance initialization:实例初始化
{
i = 47;
}
public String toString() {
if(s4 == null) // Delayed initialization:惰性初始化:就在真要使用这些对象之前初始化,称之为惰性初始化
// 在生成对象不值得及不必每次都生成对象的情况下,这种方式可以减少额外的负担
s4 = "Joy";
return
"s1 = " + s1 + "\n" +
"s2 = " + s2 + "\n" +
"s3 = " + s3 + "\n" +
"s4 = " + s4 + "\n" +
"i = " + i + "\n" +
"toy = " + toy + "\n" +
"castille = " + castille;
}
public static void main(String[] args) {
Test b = new Test();
System.out.println(b);
}
}
2.
package test;
class Cleanser {
private String s = "Cleanser";
public void append(String a) { s += a; }
public void dilute() { append(" dilute()"); }
public void apply() { append(" apply()"); }
public void scrub() { append(" scrub()"); }
public String toString() { return s; }
public static void main(String[] args) {
Cleanser x = new Cleanser();
x.dilute(); x.apply(); x.scrub();
System.out.println(x);
}
}
public class Test extends Cleanser {
// Change a method:
public void scrub() {
append(" Test.scrub()");
super.scrub(); // Call base-class version
}
// Add methods to the interface:
public void foam() { append(" foam()"); }
// Test the new class:
public static void main(String[] args) {
Test x = new Test();
x.dilute();
x.apply();
x.scrub();
x.foam();
System.out.println(x);
System.out.println("Testing base class:");
/* cleanser.main(args);main虽然是一个主函数,但同时它也是一个静态方法,这里就是一个静态方法的调用,
即调用cleaner的静态方法main*/
Cleanser.main(args);
}
}
2.1初始化基类
子类在调用其构造函数之前都是先完成基类的构造函数初始化。
基类的构造器:(1)总是会被调用;(2)在子类构造器之前被调用(不管子类有没有构造函数)
无参数构造器:
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
*///:~
带参数的构造器:
package test;
class Game {
Game(int i) {
System.out.println("Game constructor");
}
}
class BoardGame extends Game {
BoardGame(int i) {
super(i);
System.out.println("BoardGame constructor");
}
}
public class Test extends BoardGame {
Test() {
super(2);
System.out.println("Test constructor");
}
public static void main(String[] args) {
Test x = new Test();
}
} /* Output:
Game constructor
BoardGame constructor
Test constructor
*///:~
参考文章:
在讲之前,一些基本知识是应该具备的:
1、如果一个类中没有定义构造器,编译器在编译时会自动加上默认无参构造器:
public ClassName {}
2、this 和 super 的区别。
3、每个类直接或间接是Object的子类,Object只有一个无参构造方法。
4、编译器会在每个构造方法的第一行隐式添加父类的默认无参构造器,即添加super()。
新手容易犯的错误:
class Employee extends Object {
public Employee(int id) {
}
}
class Teacher extends Employee {
public Teacher() {
}
}
以上代码会产生编译错误:
Implicit super constructor Employee() is undefined. Must explicitly invoke another constructor
因为父类定义了一个带参数的构造器,因此编译器不会添加默认无参构造方法,但是因为在子类的构造器中没有显式调用父类的某个构造方法,因此编译器会自动添加super()方法, 但是父类中不存在默认无参构造方法,因此会提示默认无参构造方法未定义错误。
修改后的代码:
class Employee {
public Employee(int id) {
}
}
class Teacher extends Employee {
public Teacher() {
super(10);
}
}
这样,在子类的构造器中显式调用了父类的某个构造器,所以编译器不会自动添加super()方法。
构造器的访问修饰符:
一般可以用public,protected,default和private修饰,但是对于private,子类是无法调用该类构造器的。
多层次调用父类构造方法:
假设我们有这样一个层次结构:
Object->Employee->Teacher->Professor
class Employee {
public Employee() {
System.out.println("Employee constructor called");
}
}
class Teacher extends Employee {
public Teacher() {
System.out.println("Teacher constructor called");
}
}
class Professor extends Teacher {
public Professor() {
System.out.println("Professor constructor called");
}
}
public class Test {
public static void main(String args[]) {
Employee p = new Professor();
}
}
打印结果:
Employee constructor called
Teacher constructor called
Professor constructor called
在创建Professor对象时(new Professor()),首先会找到该类的无参构造方法,然后首先调用super()方法,调用Teacher类的无参构造方法,接着再调用Employee的无参构造方法,最后再调用Object的无参构造方法。最后再打印出信息。
3.代理
4.结合使用组合和继承
package test;
class Plate {
Plate(int i) {
System.out.println("Plate constructor");
}
}
class DinnerPlate extends Plate {
DinnerPlate(int i) {
super(i);
System.out.println("DinnerPlate constructor");
}
}
class Utensil {
Utensil(int i) {
System.out.println("Utensil constructor");
}
}
class Spoon extends Utensil {
Spoon(int i) {
super(i);
System.out.println("Spoon constructor");
}
}
class Fork extends Utensil {
Fork(int i) {
super(i);
System.out.println("Fork constructor");
}
}
class Knife extends Utensil {
Knife(int i) {
super(i);
System.out.println("Knife constructor");
}
}
// A cultural way of doing something:
class Custom {
Custom(int i) {
System.out.println("Custom constructor");
}
}
public class Test extends Custom {
private Spoon sp;
private Fork frk;
private Knife kn;
private DinnerPlate pl;
public Test(int i) {
super(i + 1);
sp = new Spoon(i + 2);
frk = new Fork(i + 3);
kn = new Knife(i + 4);
pl = new DinnerPlate(i + 5);
System.out.println("Test constructor");
}
public static void main(String[] args) {
Test x = new Test(9);
}
} /* Output:
Custom constructor
Utensil constructor
Spoon constructor
Utensil constructor
Fork constructor
Utensil constructor
Knife constructor
Plate constructor
DinnerPlate constructor
Test constructor
*///:~
4.1确保正确清理
要点:The order of cleanup is the reverse of the order of initialization
package test;
class Shape {
Shape(int i)
{ System.out.println("Shape constructor"); }
void dispose()
{ System.out.println("Shape dispose"); }
}
class Circle extends Shape {
Circle(int i) {
super(i);
System.out.println("Drawing Circle");
}
void dispose() {
System.out.println("Erasing Circle");
super.dispose();
}
}
class Triangle extends Shape {
Triangle(int i) {
super(i);
System.out.println("Drawing Triangle");
}
void dispose() {
System.out.println("Erasing Triangle");
super.dispose();
}
}
class Line extends Shape {
private int start, end;
Line(int start, int end) {
super(start);
this.start = start;
this.end = end;
System.out.println("Drawing Line: " + start + ", " + end);
}
void dispose() {
super.dispose();
System.out.println("Erasing Line: " + start + ", " + end);
}
}
public class Test extends Shape {
private Circle c;
private Triangle t;
private Line[] lines = new Line[3];
public Test(int i) {
super(i + 1);
for(int j = 0; j < lines.length; j++)
lines[j] = new Line(j, j*j);
c = new Circle(1);
t = new Triangle(1);
System.out.println("Combined constructor");
}
public void dispose() {
System.out.println("Test.dispose()");
/*The order of cleanup is the reverse
of the order of initialization:*/
t.dispose();
c.dispose();
for(int i = lines.length - 1; i >= 0; i--)
lines[i].dispose();
super.dispose();
}
public static void main(String[] args) {
Test x = new Test(47);
try {
// Code and exception handling...
} finally {
x.dispose();
}
}
}
参考资料:Java finalize方法使用
4.2名称屏蔽
package test;
class Homer {
char doh(char c) {
System.out.println("doh(char)");
return 'd';
}
float doh(float f) {
System.out.println("doh(float)");
return 1.0f;
}
}
class Milhouse {}
class Bart extends Homer {
void doh(Milhouse m) {
System.out.println("doh(Milhouse)");
}
}
public class Test {
public static void main(String[] args) {
Bart b = new Bart();
b.doh(1);
b.doh('x');
b.doh(1.0f);
b.doh(new Milhouse());
}
}
参考资料:java中重写、覆盖,重载三者的区别?
首先要明确Java中重写,覆盖,重载都是针对方法的几个不同概念。其中重写与覆盖等同,只是两种不同的称法而已。
现在主要来理解下重写与重载的区别?
以前的理解是:
重写就是保证跟父类原有方法的返回值,方法名,参数列表一致的前提下,在子类中将函数重新实现一遍。
而重载就是指返回值和方法名相同,参数列表不同的函数的实现。
现在细化下理解:
方法重写(Overriding),是继承与实现中的一个概念,主要指抽象方法的重写。
方法重载(Overloading)
两者都是Java中多态性一个的一个体现,方法重写是父类与子类之间多态性的体现,而方法重载主要是类内部多态性的一个体现。
看如下例子:
例1:
1
2
3
4
5
6
7
8
9
10
|
class
FatherCat
{
void
eat(){};
//method_1
}
class
Cat
extends
FatherCat
{
void
eat(){};
//method_2
void
eat(String fish){};
//method_3
}
|
1
2
3
4
5
6
7
8
9
10
|
abstract
class
Animal
{
abstract
void
eat();
//method_1
}
class
Cat
extends
Animal
{
void
eat(){};
//method_2
void
eat(String fish){};
//method_3
}
|
1
2
3
4
5
6
7
8
9
10
|
interface
Animal
{
abstract
void
eat();
//method_1
}
class
Cat
implements
Animal
{
public
void
eat(){};
//method_2
void
eat(String fish){};
//method_3
}
|
三个方法之间的关系如下:
method_1与method_2:
重写关系,子类Cat重写父类FatherCat的eat()方法。
method_2与method_3:
重载关系,再加一个参数列表不同方法名相同的方法。
method_1与method_3:
本来没什么关系,若硬是要扯上关系可看成重载关系(个人理解)。
具体区别有人罗列为:
重写(override)又名覆盖:
1.不能存在同一个类中,在继承或实现关系的类中;
2. 名相同,参数列表相同,方法返回值相同,
3.子类方法的访问修饰符要大于父类的。
4.子类的检查异常类型要小于父类的检查异常。
重载(overload)
1.可以在一个类中也可以在继承关系的类中;
2.名相同;
3.参数列表不同(个数,顺序,类型) 和方法的返回值类型无关。
重写就是再写一遍,重载就是再加一个。
final关键字
final数据
package test;
import java.util.*;
class Value {
int i; // Package access
public Value(int i) { this.i = i; }
}
public class Test {
private static Random rand = new Random();
private String id;
public Test(String id) { this.id = id; }
// Can be compile-time constants:
private final int valueOne = 9;
private static final int VALUE_TWO = 99;
// Typical public constant:
public static final int VALUE_THREE = 39;
// Cannot be compile-time constants:
// INT_5的值不会因为通过创建第二个FinalData对象而加以改变,这是因为
// 它是static的,在加载的时候就已经初始化了,而不是每次创建新对象时初始化
// 但是i4刚好与其相反
/* output:
* fd1: i4 = 14, INT_5 = 9
fd2: i4 = 9, INT_5 = 9
*/
private final int i4 = rand.nextInt(20);
static final int INT_5 = rand.nextInt(20);
// 以下两个都是带有编译时数值的final基本类型,没有重大区别
private Value v1 = new Value(11);
private final Value v2 = new Value(22);
/*典型的对常量进行定义的方式:
* 定义为:public,则可以被用于包之外
* 定义为:static,则强调只有一份
* 定义为:final,则说明是一个常量
* 注意定义为static final的要注意其命名规则:大写+下划线
* */
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) {
Test fd1 = new Test("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 < fd1.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];
System.out.println(fd1);
System.out.println("Creating new Test");
Test fd2 = new Test("fd2");
System.out.println(fd1);
System.out.println(fd2);
}
}
空白final
package test;
class Poppet {
private int i;
Poppet(int ii) { i = ii; }
}
public class Test {
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 Test() {
j = 1; // Initialize blank final
p = new Poppet(1); // Initialize blank final reference
}
public Test(int x) {
j = x; // Initialize blank final
p = new Poppet(x); // Initialize blank final reference
}
public static void main(String[] args) {
new Test();
new Test(47);
}
}
final参数
package test;
class Gizmo {
public void spin() {}
}
public class Test {
// 这一特性主要用来想匿名内部类传递数据
void with(final Gizmo g) {
// g = new Gizmo(); // Illegal -- g is final
// The final local variable g cannot be assigned.
// It must be blank and not using a compound assignment
}
void without(Gizmo g) {
g = new Gizmo(); // OK -- g not final
g.spin();
}
// void f(final int i) { i++; } // Can't change
// You can only read from a final primitive:
int g(final int i) { return i + 1; }
public static void main(String[] args) {
Test bf = new Test();
bf.without(null);
bf.with(null);
}
}