java构造函数
java类库的设计者们通过提供一种被称为构造函数的特殊方法,来保证每个对象都能得到初始化。Java在对象刚刚创建,用户还来不及得到的时候,自动调用构造函数。这样初始化就有保证了。
无参数的构造函数(默认的构造函数)用于创建“基本对象”,如果定义的类中没有定义构造函数,那么编译器会自动为你创建一个默认的构造函数。当类中定义了构造函数(不管带不带参数),编译器就不会再自动创建默认的构造函数了。
当你为同一个类撰写多个构造函数的时候,为避免重复,经常会在一个构造函数里调用另一个构造函数,你可以通过用this关键字来进行这种调用。但是只能调用一次,并且必须放在程序的最前面调用构造函数。
this关键字只能用于方法内部,它负责返回当前方法所在类的对象的reference。
一个子类的构造函数必须调用超类的构造函数,并且作为第一条语句。如果超类有可访问的无参数的构造函数(可以是程序员定义的或系统默认的无参数的构造函数),那么编译器会自动调用这个无参数的构造函数;
如果基类中没有默认的构造函数(也就是无参数的构造函数),或者你要调用的基类构造函数是带参数的,你就必须用super关键字以及合适的参数明确的调用基类的构造函数。
Class Alpha{
Alpha(int n){}
}
class Zeta extends Alpha{
Zeta(){
n=1;//错误,没有Alpha的构造函数被调用
}
private int n;
}
没有无参数的构造函数,所以Zeta的构造函数必须显示的调用Alpha的带参数的构造函数。正确代码为
class Zeta extends Alpha{
Zeta(){
Super(-1); //正确,Alpha的构造函数被调用
n=1; }
private int n; }
在创建派生类对象的过程中,基类的构造函数总是先得到调用,这样一级一级的追溯上去,每个基类的构造函数都会被调用。因为构造函数有一个特殊的任务:它要知道对象是不是被正确地创建了。派生类只能访问他自己的成员,它看不到基类的成员(因为它们通常都是private的)。只有基类的构造函数才知道怎样初始化它的成员,同时也只有它才有权限进行初始化。因此“把所有的构造函数都调用一遍”就变得非常重要了,否则对象就没法创建了。这就是为什么编译器会强制每个派生类都要调用基类的构造函数的原因了。如果你不在派生类的构造函数里明确的调用基类的构造函数,那么编译器就会悄悄地调用那个默认的构造函数。如果没有默认构造函数,编译器就会报错。
java继承问题
class Parent
{
private void test()
{
System.out.print("private test");
}
public static void main(String[] args)
{
Parent p=new Child();
p.test();
}
}
class Child extends Parent
{
public void test()
{
System.out.print("public test");
}
}
输出结果为“private test“。
private方法对子类隐藏,因此Child类中的test()方法是一个全新的方法。
如果Parent类中定义的test()方法为非private,那么父类、子类的test方法声明相同,子类的方法重写了父类的方法,重写的结果就是覆盖了父类方法。
如果如果Parent类中定义的test()方法为非private,并且改写父类、子类中test方法的声明,使其参数类型有所区别,这样子类的方法重载了父类的方法。
package com;
public class Cookie {
public Cookie() {
System.out.println("Cookie constructor");
}
void foo() {
System.out.println("foo");
}
}
import com.*;
public class ChocolateChip extends Cookie {
public ChocolateChip() {
System.out.println(
"ChocolateChip constructor");
}
public static void main(String[] args) {
ChocolateChip x = new ChocolateChip();
x.foo(); // 不能访问foo()方法。
}
}
继承有一个有趣的特性,就是如果Cookie类里有一个foo()方法,那么所有继承Cookie的类里也都有foo()方法。但是foo()是package权限的,并且也在另一个package里面,因此我们没法用。
将Cookie改为如下代码后,能够访问foo()方法
package com;
public class Cookie {
public Cookie() {
System.out.println("Cookie constructor");
}
protected void foo() {
System.out.println("foo");
}
}
继承类除了能访问父类的public成员外,还可以访问父类的protected成员(但是不能访问private成员)。
同一个package里的其它类可以访问这个package的public、protected、package成员。
当你继承一个类时,你也创建了一个新的类,这个新的类不仅包含了已有类的所有成员(尽管private成员已经隐藏起来了,是不能访问的),更重要的是它复制了基类的接口。于是所有能够传给基类的消息也都可以传给派生类。
继承设计方面有一条通用准则:把基类的数据设成private,方法都设成public。
file 1 :
Package p1;
class Alpha{
public Alpha() {}
}
file 2:
package p2;
import p1.*;
class Zeta{
Zeta(){
Alpha a=new Alpha();//错误
}
}
虽然构造函数Alpha有一个公共作用域,但封装它的类只有包作用域。所以,构造函数只有在包p1中可见,封装类Alpha只在包p1中可见。
public class Parent {
public int addValue( int a, int b) {
int s;
s = a+b;
return s;
}
}
class Child extends Parent {
public void addValue (){// do something...}
public int addValue( int a ){// do something...}
}
继承是子类和父类之间的关系,重载是同一类中的同名方法(参数不同)之间的关系。
这个例子,子类继承了父类的 addValue( int a, int b) 方法,就是说子类也有这个方法。
同时子类也声明了两个同名的方法 addValue( int a)和addValue( ),这两个方法则是子类从父类继承来的addValue( int a, int b)方法的重载。
当一个子类从父类继承时,父类的所有成员成为子类的成员,此时对父类成员的访问状态由继承时使用的继承限定符决定。
1.如果子类从父类继承时使用的继承限定符是public,那么
(1)父类的public成员成为子类的public成员,允许类以外的代码访问这些成员;
(2)父类的private成员仍旧是父类的private成员,子类成员不可以访问这些成员;
(3)父类的protected成员成为子类的protected成员,只允许子类成员访问;
2.如果子类从父类继承时使用的继承限定符是private,那么
(1)父类的public成员成为子类的private成员,只允许子类成员访问;
(2)父类的private成员仍旧是父类的private成员,子类成员不可以访问这些成员;
(3)父类的protected成员成为子类的private成员,只允许子类成员访问;
3.如果子类从父类继承时使用的继承限定符是protected,那么
(1)父类的public成员成为子类的protected成员,只允许子类成员访问;
(2)父类的private成员仍旧是父类的private成员,子类成员不可以访问这些成员;
(3)父类的public成员成为子类的protected成员,只允许子类成员访问;