构造方法
概念了解
Java构造函数,也叫构造方法,是JAVA中一种特殊的函数。与函数名相同,无返回值。
作用:一般用来初始化成员属性和成员方法的,即 new 对象产生后,就调用了对象的属性和方法。
几点说明
1、构造方法是新建实例时执行的特殊方法
例如我们上一章新建 Soldier 类时也就调用一个构造方法
s1 = new Soldier();
2、一个类必须有构造方法,如果不写构造方法,编辑器编译代码时,会默认添加一个构造方法,如下:
public class A(){
//添加的默认无参空方法,没有返回类型
public A(){
}
}
3、构造方法可以有多个,但参数不一样,称为构造方法的重载。这样增加了程序的灵活性
public class A(){
public A(int i){
...
}
public A(double d){
...
}
public A(int i,double d){
...
}
}
如果类中有显示的构造方法,那么默认构造方法将无效。也就是创建实例时,就不能写new A();
因为已经写了构造参数,运行时就不会再添加默认的构造方法。所以如果有显示的构造方法,还想保留默认构造 方法,需要显示的写出来。一个好的编程习惯是要保留默认的构造方法。(为了方便一些框架代码使用反射来创建对象)。
4、构造方法的作用,通常用来给成员变量赋值
给对象初始化数据可以使用构造方法或 setter 方法,通常情况下,两者都会保留
5、构造方法的名称必须与类名完全相同,构造方法不允许声明返回值
6、super(); 表示调用父类的构造方法,只有在子类的构造方法中,才能调用父类的构造方法。其中super(); 必须在有效代码的第一行,上边写注释是可以的,但不能放其他非注释代码
举例说明构造方法
首先我们创建一个宠物狗类,它的成员属性有 名字(name)、饥饿度(hungry)、快乐度(happy)。当我们喂食(feed)时,它的饥饿度降低。当我们陪它玩耍(play)时,饥饿度增高,快乐度增高。当我们惩罚(punish)它时快乐度降低。
Dog
public class Dog {
public String name;//名字
public int hungry;//饥饿度
public int happy;//快乐度
//喂食
public void feed(TextView textView) {
if (hungry == 0) {
textView.setText(name + "吃饱了\n" + textView.getText());
return;
}
hungry -= 10;
textView.setText("给" + name + "喂食,hungry:" + hungry + "\n" + textView.getText());
}
//玩
public void play(TextView textView) {
if (hungry == 100) {
textView.setText(name + "很饿了\n" + textView.getText());
return;
}
happy += 10;
hungry += 10;
textView.setText("陪" + name + "玩耍,happy:" + happy + ",hungry:" + hungry + "\n" + textView.getText());
}
//惩罚
public void punish(TextView textView) {
happy -= 10;
textView.setText("打" + name + "," + name + "哭叫:汪,happy:" + happy + "\n" + textView.getText());
}
}
xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:columnCount="4"
android:orientation="vertical"
android:rowCount="6">
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="doClick"
android:text="创建宠物狗" />
<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="doClick"
android:text="play" />
<Button
android:id="@+id/button3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="doClick"
android:text="feed" />
<Button
android:id="@+id/button4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="doClick"
android:text="punish" />
<TextView
android:id="@+id/textView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="#222222"
android:textSize="18sp"/>
</LinearLayout>
MainActivity
public class MainActivity extends AppCompatActivity {
Dog dog;
Button create;
Button play;
Button feed;
Button punish;
TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
create = (Button) findViewById(R.id.button1);
play = (Button) findViewById(R.id.button2);
feed = (Button) findViewById(R.id.button3);
punish = (Button) findViewById(R.id.button4);
textView = (TextView) findViewById(R.id.textView);
}
public void doClick(View view) {
switch (view.getId()) {
case R.id.button1:
f1();
break;
case R.id.button2:
f2();
break;
case R.id.button3:
f3();
break;
case R.id.button4:
f4();
break;
}
}
private void f1() {
dog = new Dog();
dog.name = "蠢狗";
dog.hungry = 50;
dog.happy = 50;
textView.setText("电子狗已经创建");
}
private void f2() {
dog.play(textView);
}
private void f3() {
dog.feed(textView);
}
private void f4() {
dog.punish(textView);
}
}
运行程序:
例子1:给Dog类添加无参构造方法
public class Dog {
public String name;//名字
public int hungry;//饥饿度
public int happy;//快乐度
//构造方法
public Dog() {
Log.d("Dog", "执行了构造方法");
}
//喂食
......
}
那么在点击创建宠物狗按钮来创建 Dog 类时,会执行Log输出
例子2,给Dog类添加有参构造方法
public class Dog {
public String name;//名字
public int hungry;//饥饿度
public int happy;//快乐度
//构造方法
public Dog(String name, int hungry, int happy) {
//如果局部变量与成员变量同名,必须用this.xx来引用成员变量,如果不同名,可以直接写
this.name = name;
this.happy = hungry;
this.happy = happy;
}
//喂食
......
}
那么我们创建 Dog 类对象的写法需要改成这样:
dog = new Dog("蠢狗",50,50);
例子3,给Dog类同时添加无参和有参构造方法
public class Dog {
public String name;//名字
public int hungry;//饥饿度
public int happy;//快乐度
//构造方法
public Dog() {
}
public Dog(String name, int hungry, int happy) {
//如果局部变量与成员变量同名,必须用this.xx来引用成员变量
this.name = name;
this.happy = hungry;
this.happy = happy;
}
//喂食
......
}
创建Dog对象的时候写法有两种
dog = new Dog("蠢狗",50,50);
dog = new Dog();
关键字 this
this
关键字指向的是当前对象的引用
调用类中的属性
this.属性名称,指的是访问类中的成员变量,用来区分成员变量和局部变量(重名问题)
比如我们上边的 Dog 类,类中的成员变量和构造方法中的成员变量是重名的,所以用 this.属性名称
访问类中的成员变量,以此区分
调用类中的方法:this.方法名称
,用来访问本类的成员方法
调用类构造方法:this();
访问本类的构造方法,()
中可以有参数的。如果有参数,就是调用指定的有参构造。但需要注意两点:
1.this()
不能使用在普通方法中,只能写在构造方法中
2.必须是构造方法中的第一条语句
举例说明 this 关键字
我们创建一个学生类 Student。属性包括唯一编号(id)、姓名(name)、性别(gender)、年龄(gender)
public class Student {
public int id;
public String name;
public String gender;
public int age;
//无参构造方法
public Student() {
}
//有参构造方法
public Student(int id, String name) {
//减少代码重复,调用3个参数方法,没有的参数gender可以传默认值null
/*this.id = id;
this.name = name;*/
this(id, name, null);
}
public Student(int id, String name, String gender) {
//减少代码重复,调用3个参数方法,没有的参数age可以传默认值0
/* this.id = id;
this.name = name;
this.gender = gender;*/
this(id, name, gender, 0);
}
public Student(int id, String name, String gender, int age) {
this.id = id;
this.name = name;
this.gender = gender;
this.age = age;
}
public String toString() {
return "\n姓名:" + name + "\n性别:" + gender + "\n年龄:" + age + "\nid:" + id;
}
}
xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="doClick"
android:text="student()" />
<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="doClick"
android:text="student(id,name)" />
<Button
android:id="@+id/button3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="doClick"
android:text="student(id,name,gender)" />
<Button
android:id="@+id/button4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="doClick"
android:text="student(id,name,gender,age)" />
<TextView
android:id="@+id/textView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="#222222"
android:textSize="18sp" />
</LinearLayout>
MainActivity
public class MainActivity extends AppCompatActivity {
Button create;
Button button1;
Button button2;
Button button3;
TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
create = (Button) findViewById(R.id.button1);
button1 = (Button) findViewById(R.id.button2);
button2 = (Button) findViewById(R.id.button3);
button3 = (Button) findViewById(R.id.button4);
textView = (TextView) findViewById(R.id.textView);
}
public void doClick(View view) {
switch (view.getId()) {
case R.id.button1:
f1();
break;
case R.id.button2:
f2();
break;
case R.id.button3:
f3();
break;
case R.id.button4:
f4();
break;
}
}
private void f1() {
Student s = new Student();
textView.setText(s.toString());
}
private void f2() {
Student s = new Student(9527, "张三");
textView.setText(s.toString());
}
private void f3() {
Student s = new Student(9528, "lili", "女");
textView.setText(s.toString());
}
private void f4() {
Student s = new Student(9529, "苏菲", "女", 22);
textView.setText(s.toString());
}
}
运行程序:
方法重载 Overload
重载(Overloading)的定义:如果有两个方法的方法名相同,但参数不一致,那么可以说一个方法是另一个方法的重载。
在上边 举例说明 this 关键字 的例子中,Student 类我们写了 4 个构造方法,有无参的构造方法、有只能传 id 和 name 的构造方法、还有能传 id、name 和 gender 的构造方法。这就是构造方法的重载。