public class Doctor {
public String name; //成员变量
public int age;
//无参构造
public Doctor() {
super(); //访问object类无参构造,一个类代码里没指定父类,默认继承Object类
}
//带参构造,也可看作是构造函数的重载
public Doctor(String name, int age) {
super();
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public void talk(){
int x = 8; //此处举例x是局部变量,随着方法进栈,不会默认初始化,必须手动赋值
...
}
}
构造函数:创建对象时调用的函数,给对象初始化。成员变量默认初始化值如 int是0 String 是 null
代码里提供了两种构造函数,带参和不带参,那么创建Doctor类有两种方式(实际开发中可以根据需要创建构造函数和new对象)
Doctor d1 = new Doctor();
Doctor d2 = new Doctor("Tom",30);
相应的对成员变量赋值的话,第二种是创建对象时已经赋值了,第一种需要用到set方法,如 d1.setName("华佗")
此方法是没有返回值的,方法里面的this就是哪个对象调用这个方法,指的就是这个对象。相当于new Doctor().setName("华佗")
传参“华佗”赋值给new出来的Doctor d1的成员变量name,值赋给它
比如以后的方法中需要用到name的值,可以通过get方法拿到String s = d1.getName();
返回前面d1的成员变量name的值
ps成员变量与局部区别:
1、成员变量定义在类中,整个类中都可以访问;局部变量定义在函数、语句、局部代码块中,只在所属代码块中有效
2、成员变量存在于堆内存的对象中;局部变量存在于栈内存的方法中
3、成员变量随着对象的创建而存在,对象的消失而消失;局部变量随着所属区域的执行而存在,所属区域的结束而释放
4、成员变量有默认的初始化值;局部变量没有默认初始化值,必须赋值,否则编译报错
创建对象的实例化过程中在内存中的分配:
public static void main(String[]args){
Doctor d1=new Doctor(“华佗”,30);
}
1 程序运行时main函数先进栈,对变量Doctor d1在栈中开辟空间,是引用变量
2 JVM读取指定路径下的Doctor.class文件,类加载器将Doctor类信息加载进方法区(有父类会先加载父类)
在这个类的方法区,构造方法Doctor()有相应地址值
3 在堆中给对象开辟内存空间,分配地址值,
在该内存空间中对成员变量进行默认初始化,构造方法的引用标记,指向方法区的构造方法
4 调用构造函数,对新建的对象成员变量进行赋值“华佗” 30
5 初始化完毕后堆中地址值指向栈中的 d1
如果有直接父类,在第四步调用子类构造函数时会先调用父类构造函数进行初始化,父类初始化完毕后,子类再进行显示初始化
public class SuperTest {
public static void main(String[]args) {
Son s = new Son();
}
}
class Cat {
Cat(String s){
System.out.println(s);
}
}
class Father{
Cat c = new Cat("父亲的猫");
public Father() {
System.out.println("父类");
}
}
class Son extends Father{
Cat cc = new Cat("儿子的猫");
public Son() {
System.out.println("子类");
}
}
构造函数以外可以是代码块,他们在一个类里面,每次创建这个类的对象,调用构造函数时,都会先执行代码块,无论代码块在构造函数的上面还是下面。
public class SuperTest {
public static void main(String[]args) {
Son s = new Son();
}
}
class Cat {
Cat(){
System.out.println("Cat");
}
}
class Father{
public Father() {
System.out.println("父类");
}
{
Cat c = new Cat();
System.out.println("代码块在构造函数下面也会先执行");
}
}
class Son extends Father{
Cat cc = new Cat();
public Son() {
System.out.println("子类");
}
}
一个类中如果没定义过构造函数,那么编译后系统会给一个默认的空参数构造函数。
public class SuperTest {
public static void main(String[]args) {
Son s = new Son();
}
}
class Father{ //这里不写无参/带参构造函数,系统默认给无参构造函数
}
class Son extends Father{
public Son() {
//super(); 在这里写不写都可以,不写也会默认去调用父类无参构造函数
System.out.println("子类无参访问父类无参");
}
public Son(String s) {
super("子类带参访问父类带参"); //报错父类带参构造函数没有被定义过
System.out.println("子类带参不再访问父类带参");
}
}
如果一个类定义了有参构造函数,没定义过无参构造函数,后面new出来的对象想调用无参构造函数,如new 类名()会报错。
public class SuperTest {
public static void main(String[]args) {
Father f = new Father(); //比如创建对象无参,这里会报错the constructor father() is undefined
}
}
class Father{
public Father(String s) {
System.out.println("父类带参构造");
}
}
因为有了有参构造函数,编译后系统将不会再给默认的空参数构造函数。所以建议最好每次构造函数给出无参构造,无论有无带参构造函数,用到哪种可以调用哪种。也方便子类继承无参构造。
继承中的构造函数:
如果子类构造器没有显式地调用父类的构造器,则将自动调用父类的默认无参构造器。
如果父类没有无参构造器,有带参构造器,在子类的构造器中又没有显式地调用父类的带参构造器,则java编译器将报告错误。
public class SuperTest {
public static void main(String[]args) {
Son s = new Son();
}
}
class Father{
public Father(String s) {
System.out.println("父类带参构造");
}
}
class Son extends Father{
public Son() {
super(); //这一行编译期会报错,父类无参构造函数没有被定义过
System.out.println("子类无参访问父类带参");
}
public Son(String s) {
super("子类带参访问父类带参");
System.out.println("子类带参不再访问父类带参");
}
}
父类只有带参构造,每个子类(带参或无参)第一行必须访问父类带参。不写的话默认调用父类空参,而父类空参没有创建,会报错。
可通过两种方式访问,第一种如下都是super(带参)
public class SuperTest {
public static void main(String[]args) {
Son s = new Son();
}
}
class Father{
public Father(String s) {
System.out.println("父类带参构造");
}
}
class Son extends Father{
public Son() {
super("子类无参访问父类带参");
System.out.println("子类无参访问父类带参");
}
public Son(String s) {
super("子类带参访问父类带参");
System.out.println("子类带参不再访问父类带参");
}
}
第二种:一个子类A构造访问过了super(带参)另一个子类B通过this(...)调其他子类A去访问父类带参,this语句只能放在构造函数的第一行,因为初始化动作要先执行。
public class SuperTest {
public static void main(String[]args) {
Son s = new Son();
}
}
class Father{
public Father(String s) {
System.out.println("父类带参构造");
}
}
class Son extends Father{
public Son() {
this("子类无参访问另一个我带参子类来访问父类带参");
System.out.println("子类无参访问父类带参");
}
public Son(String s) {
super("子类带参访问父类带参");
System.out.println("子类带参不再访问父类带参");
}
}
网友评论