Java构造函数
一、构造函数
特点:
//构造函数是多个,在new对象调用的时候匹配上哪个,则调用哪个
1) 在类对象创建的时候执行,而且只执行一次
2) 和类名相同
3) 没有返回值, 连void也不行
public class Japan {
void Japan() { //这个不是构造函数,虽然它编译不报错
}
}
4) 不能手工调用
5) 可以重载,不可以重写
6) 如果设计一个类的时候,没有设计构造函数,则它会生成一个默认的,无参的空构造函数
7) 如果自已定义了一个构造函数,则系统就不再生成默认的构造函数了
8) 最主要的作用,是用来对类对象进行初始化
public class Japan {
Japan(){
//系统默认的
System.out.println("无参的构造函数被调用了");
}
Japan(String msg){
System.out.println("这是我的主人让我说的话:"+msg);
}
int age;
String name;
String country;
void speak(){
System.out.println("北海道是中国领土");
}
}
class Test{
public static void main(String[] args) {
Japan japan=new Japan(); //调用无参的构造函数
Japan japan2=new Japan("这是传入的参数");
//调用带参的构造函数
}
}
//例子,使用构造函数传参
//通过构造函数来解决参数的初始化问题
public class TV {
private int width;
private int height;
private String pinpai; //品牌
private String color; //颜色
TV(int width,int height,String pinpai,String color){
this.width=width;
//this指向类对象,前面的this.width指是类对象中的width,后面的width是参数,this起到一个类似指针的作用,以作区分
this.height=height;
this.pinpai=pinpai;
this.color=color;
}
void turnOn(){
System.out.println(pinpai+"牌电视开了");
}
void turnOff(){
System.out.println("电视冒烟了,烟是"+color+"色的");
}
void play(){
System.out.println("武打片");
}
void show(){
System.out.println("这台电视:");
System.out.println("体积:" +width*height);
System.out.println("品牌:" +pinpai);
System.out.println("颜色:" +color);
}
}
class Test2{
public static void main(String[] args) {
TV tv=new TV(200,150,"熊猫","银灰");
tv.show();
tv.turnOn();
tv.play();
tv.turnOff();
}
}
二、this关键字
this可以调用本类的属性,方法
例如:
TV(String pinpai,String color){
this.pinpai=pinpai;
//this指向类对象,前面的this.pinpai指是类对象中的pinpai,后面的pinpai是参数,this起到一个类似指针的作用,以作区分
this.color=color; //使用this 调用本类的属性
this.turnOn(); //使用this调用本类的方法
....
}
//使用this(参数列表) 可以在一个构造函数中调用本类的另一个构造函数
TV(int width,int height,String pinpai,String color){
this(pinpai, color);
//用this调用其他的构造函数,而且必须放在第一句,调用格式是this加括号直接传参
this.width=width;
this.height=height;
}
三、对象作为参数传递
1) 基本数据类型做为函数的参数
public static void main(String[] args) {
int score=59;
change(score);
System.out.println(score);
// 59 ,可以看到,对于基本数据类型,做为函数的参数,对形参的改变,不会影响到实参,因为它不共用堆内存对象,是两个栈内存
}
static void change(int score){ //函数的形参,可以视为局部变最 local
score=90;
}
2) 引用类型做为对象的参数
public class Test3 {
public static void main(String[] args) {
Student stu=new Student();
stu.score=59;
change(stu);
System.out.println(stu.score); //90
}
static void change(Student stu){
//当引用类型做为函数的参数的时候,对形参的改变,会影响到实参,因为共用堆内存对象,改变堆内存会影响..
stu.score=90;
}
}
class Student{
int score;
}
四、static关键字
static 是静态的意思
//例一 需求:统计Cat类的实例一共创建了多少
public class Cat {
Cat(){
count++;
}
static int count; //用来统计本类的实例创建了多少个
int age;
String name;
}
class Test5{
public static void main(String[] args) {
Cat c1=new Cat();
Cat c2=new Cat();
Cat c3=new Cat();
Cat c4=new Cat();
System.out.println(c4.count); //4
System.out.println(c1.count); //4
}
}
static 关键字的特点
1) 多个对象,共享同一份数据 (附:java中没有全局变量,有这种需求的时候,可以使用static关键字实现)
2) 它修饰的成员,在类加载的时候加载,并初始化,只初始化一次
3) 它可以修饰属性或方法,被它修饰的成员,可以直接用类名. (推荐) 引用,也可以用对象名. 引用, 静态成员,可以脱离对象而存在
4) 无法从静态上下文中访问非静态上下文( 在静态方法中,不可能出现this关键字 )
//例子 在实例方法中,访问了静态成员
public class Cat {
static String home="中国";
int age;
String name;
//实例方法
void talk(){
System.out.println("我的家在:"+home); //在实例方法中,访问静态成员,OK
System.out.println("我的年龄:"+age);
System.out.println("我的名字"+name);
}
}
class Test5{
public static void main(String[] args) {
Cat c=new Cat();
c.talk();
}
}
//例子,在静态上下文中,无法访问非带态上下文 (上下文: 函数,或字段)
class Cat {
static String home="中国";
int age;
String name;
//实例方法
void talk(){
System.out.println("我的家在:"+home); //ok 在实例方法中,访问静态成员,OK
System.out.println("我的年龄:"+age);
System.out.println("我的名字"+name);
}
//试图在静态方法中,访问非静态成员,出错
static void speak(){
System.out.println("我的名字是:"+age); //错误 Cannot make a static reference to the non-static field name
}
}
附: public static void main(String[] args)
-- public 表示这个函数是公共的
-- static 表示这个函数是静态的
-- void 表示这个函数没有返回值
-- main 是一个固定的名称
-- String[] 表示函数接收一个数组类型的参数
-- args 参数名称
例子 给main函数传参:
class Test{
public static void main(String [] args){
for(int i=0;i<args.length;i++){
System.out.println(args[i]); //取出传给main函数的参数
}
}
}
运行的时候 java Test 参数1 参数2 ....
五、构造代码块和静态代码块
//例子
class Sheep{
{ //构造代码块,执行早于构造函数,在对象每次创建的时候,都执行
System.out.println("构造代码块");
}
Sheep(){ //构造函数
System.out.println("构造函数");
}
static {
System.out.println("这是静态代码块");
}
}
//例子
class Test6{
public static void main(String[] args) {
Sheep sheep1=new Sheep();
Sheep sheep2=new Sheep();
}
//这是静态代码块
//构造代码块
//构造函数
//构造代码块
//构造函数
}
//例子 下面程序输出的结果
public static void main(String[] args) {
new Person(9999);
new Person();
}
class Person{
Person(){
System.out.println("a");
}
Person(int x){
System.out.println(x);
}
static{ //静态成员只初始化一次
System.out.println("b");
}
{
System.out.println("c");
}
}
//b c 9999 c a
六、类的加载和执行顺序
Cat cat=new Cat();
1) 先将Cat.class这个字节码文件,装载到内存中
2) 静态成员先初始化 (静态属性,静态代码块)
3) 在堆内存上开辟空间, 类成员默认初始化
4) 类成员显式初始化
5) 构造代码块执行
6) 构造函数执行
7) 将栈内存中的引用指向堆内存中的实体
//下面的两个静态成员,谁先初始化?谁写在前面,谁先初始化
class cat{
int age=90;
int weight=15;
String nickName="tom";
static String home="赵明明家" //静态属性
static { //静态代码块
System.out.println("喵~~");
}
}