一、构造函数
1、构造函数:
类中的构造方法用来初始化一个类,构造方法一般为公有类型,没有返回值。但是特殊情况是允许将构造函数定为私有类型即通过private修饰,如单例模式中类的构造函数就是私有的。只允许在类的内部生成对象供外部访问。
定义形式一般为:public+类名(数据类型1 变量1,数据类型2 变量2.......);当类中产生一个对象时,也就是通过关键字new一个对象时,构造方法就会被自动执行。如果程序中没有写构造方法,那么编译时会自动加上一个内部为空的构造函数。如果在一个类中编写了不为空的构造函数,那么系统就不会自动生成为空的构造函数,所以要记得编写一个为空的构造函数。
2、方法重载:
重载一般是相对于类中的方法而言的,方法重载是指在同一个类中可以有多个同名的方法,只要函数的参数列表不同即可,至于返回值类型可以相同也可以不同。
3.构造函数使用及重载:
(1)编程示例:
package com.jwang.facetoobject;
public class ConstructorAndOverload
{
//成员变量的定义
private int age;
private String name;
//无参数的构造函数
public ConstructorAndOverload()
{
age = 10;
System.out.println("无参数的构造方法正在执行。。。。。。。");
}
//构造函数重载,添加一个参数
public ConstructorAndOverload(String x)
{
name=x;
System.out.println("带一个参数的构造方法正在执行。。。。。。。");
}
//构造函数重载,添加两个参数
public ConstructorAndOverload(String x,int y)
{
name=x;
age=y;
System.out.println("带二个参数的构造方法正在执行。。。。。。。");
}
//成员方法1的定义
public void shout()
{
int age = 60;
//局部变量覆盖全局变量,所以age打印的值为60
System.out.println(name+"`s age is "+age);
System.out.println(name+"`s name is "+name);
}
//成员方法2的定义
public void shout1()
{
System.out.println(name+"`s age is "+age);
System.out.println(name+"`s name is "+name);
}
//成员方法3的定义:
public void setAge(int x)
{
if(age<0)
return;
age=x;
}
//成员方法4的定义:
public int getAge()
{
return age;
}
//成员方法4的定义,此方法接收一个对象类型的参数
public void getsomeone(ConstructorAndOverload p)
{
//这里的p是形参,new person()作为实参会传给形参。
p.shout();
}
//主函数的定义使用
public static void main(String [] args)
{
//new了一个对象p1,对象创建是会调用无参数的构造方法
ConstructorAndOverload p1=new ConstructorAndOverload();
//new了一个对象p2,对象创建会调用带两个参数的构造方法
ConstructorAndOverload p2=new ConstructorAndOverload("张三",20);
//new了一个对象p3,对象创建会调用带一个参数的构造方法
ConstructorAndOverload p3=new ConstructorAndOverload("王五");
p1.age = -30;
p1.name = "jwang";
p1.shout();
p1.shout1();
p2.shout();
p2.shout1();
//对象作为函数参数传递
p1.getsomeone(p3);
}
}
(2)测试结果:
4.java中的垃圾回收机制:
(1)如果某块内存空间没有任何引用指向它,那么虚拟机就将其认定为垃圾;这些垃圾不需要程序员自己释放,jvm自带垃圾回收机制
但虚拟机并不是随时随地地立即回收垃圾,而是在系统比较空闲的时候,才会执行回收任务。
(2)在程序中编写System.gc()可以使得垃圾回收机制回收垃圾。
5.finalize()介绍:
(1)每一个类中都有一个finalize()方法,也有一个equals()方法。因为这两个方法是Object中的,而所有类默认继承Object类
(2)当产生一个对象时,对象就会自动调用构造方法,所以当构造函数被调用的时候,就说明有对象产生了。类似的,当一个对象消亡之前,就会自动调用finalize()方法,就像人临死前要交代后事一样。所以当finalize()被调用的时候就说明有对象要消亡了。
(3)无论是构造方法还是finalize()方法被调用的时候,对象都是存在的。
(4)finalize()方法是在对象被当成垃圾从内存中释放前调用,垃圾回收器的启动不由程序员控制,也无规律可循,并不会一产生垃圾,他就被唤起,甚至有可能到程序结束他都没有被启动的机会。
(5)Java里提供了system.gc()方法,使用这个方法能够强制启动垃圾回收器来回收垃圾。
程序示例:
package com.jwang.facetoobject;
public class TestFinalized
{
// 成员变量的定义
private int age;
private String name;
// 成员方法1的定义
public void shout()
{
int age = 60;
System.out.println(name + "’s age is " + age);
}
// 成员方法2的定义:
public void setAge(int x)
{
if (age < 0)
{
return;
}
age = x;
}
// 成员方法3的定义:
public int getAge()
{
return age;
}
// 成员方法4的定义,接收对象类型的参数
public void getSomeone(TestFinalized p)
{
p.shout();// testTestFinalized类方法内部调用TestFinalized类中的方法。
}
// 成员方法5的定义:
public void fun1()
{
System.out.println(name);
}
// 成员方法6的定义:
public void fun2()
{
TestFinalized a2 = new TestFinalized("a2");
a2.fun1();
this.fun1();
/*
* this是可以省略的,直接写成fun1();也是可以的,就像同一个公司的职员在提及自己公司时省略公司名称是一个道理 a1.fun1();
* 这样调用就是错误的,因为编译时,fun2()中还不知道有a1对象,所以这里要用this,
* 指fun2()被调用时所属于的那个对象。也就是说fun2()运行时肯定是有一个对象在调用它,this就是指那个对象
*/
}
// 复写finalize()方法:
// finalize()方法在程序中的对象变成垃圾将要被垃圾回收机制回收前自动调用;
public void finalize()
{
System.out.println("垃圾回收机制已经被唤醒,正在调用finalize方法");
}
// 无参数构造方法定义来给对象的属性赋初值:
public TestFinalized()
{
age = 10;
System.out.println("============无参数的构造方法正在被调用===============");
}
// 定义一个带一个参数的构造方法
public TestFinalized(String name)
{
// this表示调用此构造函数的那个对象,this.name=name;相对于给那个对象的属性name赋初值。赋值号右面的是传进来的参数。
this.name = name;
System.out.println("============带一个参数的构造方法正在被调用===============");
}
// 定义一个带两个参数的构造方法
public TestFinalized(String name, int age)
{
/*
* this.name = name; 上面一行的代码和上一个构造方法的内容相同,可以用代码实现这个构造方法对另一个构造方法的调用,
* 通过传递的参数的个数来确定哪个构造方法被调用,也就是说当一个构造方法调用另一个构造方法的时候, 必须要用this关键字。
*/
this(name);
this.age = age;// this表示调用此构造函数的那个对象,this.age=age;相对于给那个对象的属性name赋初值
System.out.println("============带两个参数的构造方法正在被调用===============");
}
// 主函数的定义使用
public static void main(String[] args)
{
TestFinalized p1 = new TestFinalized();// new了一个对象p1
TestFinalized p2 = new TestFinalized("张三", 20);// new了一个对象p2
TestFinalized p3 = new TestFinalized("王五");
p1.age = -30;// 对象的属性赋值
p1.shout();// 对象p1调用方法
p2.shout();// 对象p2调用方法
p1.getSomeone(p3);// p1通过getSomeone()方法调用p2的shout(),这种调用时可以的
TestFinalized a1 = new TestFinalized("a1");
a1.fun2();
// 产生3个匿名对象,查看finalize()方法的作用
new TestFinalized();
System.gc();
new TestFinalized();
new TestFinalized();
System.gc();// 垃圾回收机制的调用,相当于把收垃圾的叫过来,如果不加这个代码,finalize方法可能不会立即被调用。
}
}
测试结果:
二、this及super关键字:
1、this总结:
(1)this关键字说明:
Java关键字this只能用于方法体内。当一个对象创建后,Java虚拟机(JVM)就会给这个对象分配一个引用自身的指针,这个指针的名字就是this。因此,this只能在类中的非静态方法中使用,静态方法和静态的代码块中绝对不能出现this,因为静态方法调用不需要创建对象。并且this只和特定的对象关联,而不和类关联,同一个类的不同对象有不同的this。下面给出一个使用this的综合实例,以便说明问题:
(2)this关键字的应用实例
package com.jwang.facetoobject;
public class TestAboutThis
{
private int number;
private String username;
private String password;
private int x = 100;
//定义一个带一个参数的构造方法
public TestAboutThis(int n)
{
//下面还可以写为:this.number=n;构造方法被调用肯定是产生了一个对象,所以this表示当前对象
number = n;
}
//定义一个带三个参数的构造方法
public TestAboutThis(int i, String username, String password)
{
// 成员变量和参数同名,成员变量被屏蔽,用"this.成员变量"的方式访问成员变量.
this.username = username;
this.password = password;
}
// 默认不带参数的构造方法
public TestAboutThis()
{
//不带参数的构造方法通过this调用另一个构造方法
this(0, "未知", "空");
}
//定义一个带一个参数的构造方法
public TestAboutThis(String name)
{
//带一个参数的构造方法通过this调用另一个构造方法
this(1, name, "空");
}
public static void main(String args[])
{
//产生一个实例对象,默认调用不带参数的构造方法
TestAboutThis t1 = new TestAboutThis();
//产生另一个实例对象,默认调用带一个参数的构造方法
TestAboutThis t2 = new TestAboutThis("游客");
//第一个实例对象调用成员方法,并传递引用类型的数据变量t1.
t1.outinfo(t1);
//第二个实例对象调用成员方法,并传递引用类型的数据变量t2。
t2.outinfo(t2);
}
private void outinfo(TestAboutThis t)
{
//括号里面表示该方法接受一个TestAboutThis类型的变量。
System.out.println("-----------");
System.out.println(t.number);
System.out.println(t.username);
System.out.println(t.password);
overed(); // 这个可以写为: this.overed();表示当前对象调用此方法
}
private void overed()
{
//方法被对象调用,方法中有与类中成员变量同名的局部变量时,成员变量被屏蔽,用"this.成员变量"的方式访问成员变量.
int x;
x = this.x++;
System.out.println(x);
System.out.println(this.x);
}
}
(3)运行结果展示:
(3)this使用情况总结
通过上面的例子,说明在什么情况下需要用到this:
第一、通过this调用另一个构造方法,用法是this(参数列表),这个仅仅在类的构造方法中,别的地方不能这么用。
第二、函数参数或者函数中的局部变量和成员变量同名的情况下,成员变量被屏蔽,此时要访问成员变量则需要用“this.成员变量名”的方式来引用成员变量。当然,在没有同名的情况下,可以直接用成员变量的名字,而不用this,用了也不为错,呵呵。
第三、在函数中,需要引用该函数所属类的当前对象时候,直接用this。
其实这些用法总结都是从对“this是指向对象本身的一个指针”这句话的更深入的理解而来的,死记不然容易忘记而且容易搞错,要理解!
2、super总结:
(1)super关键字说明;
super关键和this作用类似,是被屏蔽的成员变量或者成员方法或变为可见,或者说用来引用被屏蔽的成员变量和成员成员方法。
不过super是用在子类中,目的是访问直接父类中被屏蔽的成员,注意是直接父类(就是类之上最近的超类)。下面是一个综合运用super的例子,有两个类:一个Father类,一个Father类的子类Son,通过这两个类完全演示了super的用法。
(2)super关键字的应用实例:
说明:此例子仅仅为了说明super的用法,实际在设计类的时候一般都尽可能私有(private)化。
package com.jwang.facetoobject;
public class TestAboutSuperFather
{
public String v = "TestAboutSuperFather";
public String x = "输出了TestAboutSuperFather类的public成员变量x!!!";
//父类中不带参数的构造方法
public TestAboutSuperFather()
{
System.out.println("TestAboutSuperFather构造方法被调用!");
}
//父类中带一个参数的构造方法
public TestAboutSuperFather(String v)
{
this.v="TestAboutSuperFather类的带参数构造方法!运行了.";
}
//父类中outinfo()方法,不带参数
public void outinfo()
{
System.out.println("TestAboutSuperFather的outinfo方法被调用");
}
}
package com.jwang.facetoobject;
public class TestAboutSuperSon extends TestAboutSuperFather
{
public String v = "TestAboutSuperSon";
public TestAboutSuperSon()
{
// 调用超类的构造方法,只能放到第一行
super();
System.out.println("TestAboutSuperSon无参数构造方法被调用!");
}
public TestAboutSuperSon(String str)
{
super(str);
System.out.println("TestAboutSuperSon带参数构造方法被调用!");
}
// 子类重写了父类的成员方法outinfo()
public void outinfo()
{
System.out.println("TestAboutSuperSon的outinfo()方法被调用");
}
public void test()
{
String v = "哈哈哈哈!"; // 局部变量v覆盖了成员变量v和超类变量v
System.out.println("------1-----");
System.out.println(v); // 输出局部变量v
System.out.println(this.v); // 输出(子类)成员变量v
System.out.println(super.v); // 输出超类成员变量v
System.out.println("------2-----");
System.out.println(x); // 输出超类成员变量v,子类继承而来
System.out.println(super.x); // 输出超类成员变量v
System.out.println("------3-----");
outinfo(); // 调用子类的outinfo()方法
this.outinfo(); // 调用子类的outinfo()方法
super.outinfo(); // 调用父类的outinfo()方法
}
public static void main(String[] args)
{
// 创建一个匿名对象调用test方法
new TestAboutSuperSon().test();
}
}
测试结果:
(3)通过上面的例子,下面总结一下super的用法:
第一:在子类构造方法中要调用父类的构造方法,用“super(参数列表)”的方式调用,参数不是必须的。同时还要注意的一点是:“super(参数列表)”这条语句只能用在子类构造方法体中的第一行。
第二:当子类方法中的局部变量或者子类的成员变量与父类成员变量同名时,也就是子类局部变量覆盖父类成员变量时,用“super.成员变量名”来引用父类成员变量。当然,如果父类的成员变量没有被覆盖,也可以用“super.成员变量名”来引用父类成员变量,不过这是不必要的。
第三:当子类的成员方法覆盖了父类的成员方法时,也就是子类和父类有完全相同的方法定义(但方法体可以不同),此时,用“super.方法名(参数列表)”的方式访问父类的方法。
三、static关键字:
1.静态成员变量:
(1)静态成员变量的说明:
有时候,我们希望无论是否产生了对象或无论产生多少个对象的情况下,某些特定的数据在内存中只有一份,例如所有的中国人都有国家名称,每一个中国人都共享这个名称,不必在每个中国人的实例对象中都单独的分配一个用于代表国家名称的变量。比如定义一个Chinese的类,类中有一个country=“中国”的成员变量。如果在他前面加上static关键字,那么这个变量就是静态成员变量。我们可以直接使用类名来访问这个静态的成员变量,还可以在类中的非静态成员方法中像访问其他成员非静态成员变量一样去访问这个静态的成员变量,当然了也可以用对象名来访问这个静态成员变量。
(2)静态成员变量的使用示例:
package com.jwang.facetoobject;
public class TestStaticAboutProperty
{
//定义静态的成员变量
private static String country = "中国";
//定义静态的成员变量
private static int age1 = 0;
//非静态的成员变量的定义
private int age2 = 0;
//定义一个非静态的成员方法
public void singOurCountry()
{
//访问静态成员变量的第一种方法:通过非静态的成员方法来直接访问
System.out.println("啊,亲爱的"+country);
}
@SuppressWarnings("static-access")
public static void main(String[] args)
{
//访问静态成员变量的第二种方法:通过类名直接来访问,不用产生对象
System.out.println("chinese country is"+TestStaticAboutProperty.country);
TestStaticAboutProperty ch1 = new TestStaticAboutProperty();//创建一个实例对象
//访问静态成员变量的第三种方法:通过对象名直接访问。
System.out.println("chinese country is"+ch1.country);
ch1.singOurCountry();//对象调用方法,方法访问静态成员变量。
TestStaticAboutProperty ch2 = new TestStaticAboutProperty();
TestStaticAboutProperty ch3 = new TestStaticAboutProperty();
TestStaticAboutProperty ch4 = new TestStaticAboutProperty();
System.out.println("============第一次累加之后============");
System.out.println(++ch2.age1);
System.out.println(++ch2.age2);
System.out.println("============第二次累加之后============");
System.out.println(++ch3.age1);
System.out.println(++ch3.age2);
System.out.println("============第三次累加之后============");
System.out.println(++ch4.age1);
System.out.println(++ch4.age2);
}
}
测试结果:
注意:我们不能把任何方法体内的变量声明成静态的。如:fun(){Static int i=0;}这样的定义是非法的。
2.静态成员方法
(1)静态成员方法说明:
我们有时也希望不必创建对象就可以调用某个方法,换句话说也就是使该方法不必和对象绑在一起。要实现这样的效果,只需要在类中定义的方法前面加上static关键字即可,我们称这种方法叫做静态成员方法。同静态成员变量一样
第一:可以用类名直接访问静态成员方法。
第二:也可以用类的实例对象来访问静态成员方法。
第三:还可以在类的非静态成员方法中,像访问其他非静态方法一样访问这个静态的成员方法。
(2)静态成员方法的使用:
package com.jwang.facetoobject;
public class TestStaticAboutProperty
{
//定义静态的成员变量
private static String country = "中国";
//定义静态的成员变量
private static int age1 = 0;
//非静态的成员变量的定义
private int age2 = 0;
//定义一个非静态的成员方法
public void singOurCountry()
{
//访问静态成员变量的第一种方法:通过非静态的成员方法来直接访问
System.out.println("啊,亲爱的"+country);
addTest();
}
//定义一个静态的成员方法
public static void test()
{
//静态成员方法调用静态成员方法
addTest();
}
@SuppressWarnings("static-access")
//定义一个静态的成员方法
public static void addTest()
{
TestStaticAboutProperty ch2 = new TestStaticAboutProperty();
TestStaticAboutProperty ch3 = new TestStaticAboutProperty();
TestStaticAboutProperty ch4 = new TestStaticAboutProperty();
System.out.println("============第一次累加之后============");
System.out.println(++ch2.age1);
System.out.println(++ch2.age2);
System.out.println("============第二次累加之后============");
System.out.println(++ch3.age1);
System.out.println(++ch3.age2);
System.out.println("============第三次累加之后============");
System.out.println(++ch4.age1);
System.out.println(++ch4.age2);
}
@SuppressWarnings("static-access")
public static void main(String[] args)
{
new TestStaticAboutProperty().singOurCountry();
//访问静态成员变量的第二种方法:通过创建对象来访问
new TestStaticAboutProperty().addTest();
//访问静态成员变量的第三种方法:通过类名直接访问
TestStaticAboutProperty.test();
}
}
测试结果:
注意:
(1)静态成员方法只能直接调用同类中的其他静态成员(包括静态成员变量和静态的成员方法),而不能直接访问类中的非静态成员,这是因为,对于非静态的方法和变量,需要先创建类的实例对象之后才可以被使用,而静态方法在使用前不用创建任何对象。
(2)静态成员方法不能以任何方式引用this和super关键字。与上面的道理一样,因为静态方法在使用前不用创建任何实例对象,当静态方法被调用的时候,this所引用的对象根本就还没有产生。
(3)Main()方法是静态的,因此jvm在执行main方法时不创建main方法所在类的实例对象,因而在main方法中,不能直接,访问该类中的非静态成员,必须创建该类的一个实例对象后,才能通过这个对象去访问该类中的非静态成员。