Java基础汇总(四)——代码块、构造方法

一、类和包

封装一组类、子包和接口的机制,其可以被视为数据封装(或数据隐藏)

包的作用:

  • 提供搜索和定位类、接口、枚举和注释等
  • 防止命名冲突(包采用树形目录的存储方式,同包中类的名字不同,不同包中类的名字可以相同。)
  • 访问控制(拥有包访问权限的类才能访问某个包中的类)

只有用import关键字导入相应包,才能够使用该包中的成员

常见包类型:

  • java.lang:包含语言支持类(例如分类,用于定义基本数据类型,数学运算)。该软件包会自动导入。
  • java.io:包含分类以支持输入/输出操作。
  • java.util:包含实现像链接列表,字典和支持等数据结构的实用类; 用于日期/时间操作。
  • java.applet:包含用于创建Applets的类。
  • java.awt:包含用于实现图形用户界面组件的类(如按钮,菜单等)。
  • java.net:包含支持网络操作的类。

二、.Java源文件相关知识点

  • .java源文件中可以包括多个类
  • .java源文件中只能有一个public类(编译器在编译时,针对一个.java文件只会接受一个public类,否则报错)
  • .java文件中可以没有public类
  • 包中public的类的类名必须和文件名相同(方便虚拟机在相应的路径中找到相应的类所对应的字节码文件)
  • main方法一个特殊的函数,作为程序的入口,可被JVM调用
  • (String[] args):main函数的参数,类型是一个数组,该数组中的元素为字符串数组。空数组的长度为0,但也可以在运行时向其中传入参数
  • 一个java文件中可以包含多个类,每个类中有且仅有一个主函数,但是每个java文件中可以包含多个主函数,运行时,需指定JVM入口
  • 外部类只能用public和default修饰(public 和 default 能区分该类能否被import;类被protected(仅同包内和子类可见)修饰,非同包类无法继承该包;private修饰的外部类,其他外部都无法import)
  • 类没有修饰关键词,其默认为default修饰

三、构造方法

  • 是类的一种特殊方法,用来初始化一个类的新对象
  • Java每个类都有一个默认的构造方法,其必须和类名相同
  • 没有返回类型,其默认的返回类型为对象类型本身
  • 不能被 static、final、synchronized、abstract 和 native 修饰(原因:构造方法用于初始化一个新对象,所以用 static 修饰没有意义;构造方法不能被子类继承,所以用 final 和 abstract 修饰没有意义;多个线程不会同时创建内存地址相同的同一个对象,所以用 synchronized 修饰没有必要

例1:

public class MyClass
{
    MyClass() // 定义无参的构造方法
    {
        System.out.println("无参构造方法!")
    }
    MyCiass(int m) // 定义有参的构造方法
    {
       this.m=m;
    }
}

在一个类中定义多个具有不同参数的同名方法,是方法的重载。在实例化该类时可以调用不同的构造方法进行初始化

类的构造方法不是要求必须定义的。如果在类中没有定义任何一个构造方法,则 Java 会自动为该类生成一个默认的构造方法。默认的构造方法不包含任何参数,并且方法体为空

例2:

不同的条件下使用不同的初始化行为创建类的对象,这时候就需要在一个类中创建多个构造方法

public class Worker
{
    public String name; // 姓名
    private int age;    // 年龄
    //定义带有一个参数的构造方法
    public Worker(String name)
    {
        this.name=name;
    }
    //定义带有两个参数的构造方法
    public Worker(String name,int age)
    {
        this.name=name;
        this.age=age;
    }
    public String toString()
    {
        return"大家好!我是新来的员工,我叫"+name+",今年"+age+"岁。";
    }
}

附:Object 类具有一个 toString() 方法,创建的每个类都会继承该方法。它返回一个 String 类型的字符串。如果一个类中定义了该方法,则在调用该类对象时,将会自动调用该类对象的 toString() 方法并返回一个字符串,然后使用“System.out.println(对象名)”就可以将返回的字符串内容打印出来。

四、构造方法详解

普通构造方法

  • 方法名与类名相同
  • 无返回类型
  • 子类不能继承父类的构造方法
  • 不能被static、final、abstract修饰(有final和static修饰的是不能被子类继承的,abstract修饰的是抽象类,抽象类是不能实例化的,也就是不能new)
  • 可被private修饰,可以在本类里面实例化,但是外部不能实例化对象

默认构造方法

  • 如果没有任何的构造方法,编译时系统会自动添加一个默认无参构造方法

重载构造方法

  • 原本的类里的构造方法是一个参数的,现在新建的对象是有三个参数,此时就要重载构造方法
  • 当一个类中有多个构造方法,有可能会出现重复性操作,这时可以用this语句调用其他的构造方法

例3:

public class A{
    private int age;
    private String name;
    public A(int age,String name){
        this.age=age;
        this.name=name;
    }
    public A(int age){
        this(age,"无名氏"); // 调用 A(int age,String name)构造方法
    }
    public A(){
        this(1); // 调用 A(int age)构造方法
    }
    public void setName(String name) {this.name=name;}
    public String getName() {return name;}
    public void setAge(int age) {this.age=age;}
    public int getAge() {return age;}
}

A a=new A(20,"周一");
A b=new A(20);
A c=new A();
String name = a.getName();
String name1 = b.getName();
int age = c.getAge();
System.out.println(name);
System.out.println(name1);
System.out.println(age);

五、子类构造方法调用父类构造方法

父类构造方法是绝不能被子类继承,所以子类构造方法只能通过调用来使用父类的构造方法

  • 调用父类无参构造方法
  • 当子类构造方法调用父类无参构造方法,一般都是默认不写的,要写的话就是super(),且要放在构造方法的第一句
  • 当子类构造方法要调用父类有参数的构造方法,那么子类的构造方法中必须要用super(参数)来调用父类构造方法,且要放在构造方法的第一句
  • 当子类的构造方法是无参构造方法时,必须调用父类无参构造方法。因为系统会自动找父类有没有无参构造方法,如果没有的话系统会报错
  • 当子类构造方法是有参构造方法时,若其方法中没有写super,默认调用父类无参构造方法(与子类是无参的构造方法相同)
  • 子类构造方法有super(参数)时,就调用父类有参构造方法,系统会找父类有没有参数一致(参数数量,且类型顺序要相同)的有参构造方法,如果没有的话,也会报错

六、代码块简介

普通代码块:

  • 类中方法的方法体

构造代码块

  • 构造块会在创建对象时被调用,每次创建时都会被调用,优先于类构造函数执行

静态代码块:

  • 用static{}包裹起来的代码片段,只会执行一次。静态代码块优先于构造块执行

同步代码块:

  • 使用synchronized(){}包裹起来的代码块,在多线程环境下,对共享数据的读写操作是需要互斥进行的,否则会导致数据的不一致性。同步代码块需要写在方法中

静态代码块和构造代码块的异同点:

相同点:

  • JVM加载类后且在构造函数执行之前执行,在类中可定义多个

不同点:

  • 静态代码块在非静态代码块(构造代码块)之前执行
  • 静态代码块只在第一次new时执行一次,之后不在执行,而非静态代码块(构造代码块)每new一次就执行一次

七、代码块详解

局部代码块

  • 位置:局部位置(方法内部)
  • 作用:限定变量的生命周期,尽早释放,节约内存
  • 调用:调用其所在的方法时执行

例1:

class B {
    B(){}
    public void go() {
        //方法中的局部代码块,一般进行一次性地调用,调用完立刻释放空间,避免在接下来的调用过程中占用栈空间
        //因为栈空间内存是有限的,方法调用可能会会生成很多局部变量导致栈内存不足。
        //使用局部代码块可以避免这样的情况发生。
        {
            int i = 1;
            ArrayList<Integer> list = new ArrayList<>();
            while (i < 1000) {
                list.add(i ++);
            }
            for (Integer j : list) {
                System.out.println(j);
            }
            System.out.println("gogogo");
        }
        System.out.println("hello");
    }
}

构造代码块

  • 位置:类成员的位置,就是类中方法之外的位置
  • 作用:把多个构造方法共同的部分提取出来,共用构造代码块
  • 调用:每次调用构造方法时,都会优先于构造方法执行,也就是每次new一个对象时自动调用,对对象的初始化

例2:

public class CodeBlock {
	int m = 1;
    int initValue ;//成员变量的初始化交给代码块来完成
	
	public CodeBlock() {
		System.out.println("构造器");
	}
	
	 {
        //代码块的作用体现于此:在调用构造方法之前,用某段代码对成员变量进行初始化。
        //而不是在构造方法调用时再进行。一般用于将构造方法的相同部分提取出来。
        //
        for (int m = 1; m < 101;m ++) {
            initValue += m;
        }
    }
	
	{
        System.out.println(initValue);
        System.out.println(m);//此时会打印1
        int m = 2;//代码块里的变量和成员变量不冲突,但会优先使用代码块的变量
        System.out.println(m);//此时打印2
	} 
	
	 int j = 2;
    {
        System.out.println(j);
        System.out.println(m);//代码块中的变量运行后自动释放,不会影响代码块之外的代码
    }
    
    {
        System.out.println("代码块运行");
    }
	
	public static void main(String[] args) {
		CodeBlock cb = new CodeBlock();
	}
}




public class CodeBlock {
    //构造代码块
	{
		System.out.println("构造代码块");
	}
	
    //静态构造代码块
    static{
        System.out.println("静态构造代码块");
    }
	
 	//构造器
	public CodeBlock() {
		System.out.println("构造器");
	}
  
	public static void main(String[] args) {
        //两次创建对象
		CodeBlock a = new CodeBlock();
		CodeBlock b = new CodeBlock();
	}

静态代码块

  • 位置:类成员的位置,用static修饰的代码块
  • 作用:对类进行初始化,当new多个对象时,只能加载第一个new对象,执行一次
  • 调用:new对象时自动调用,并只能调用一次

例3:

public class CodeBlock {
	 	//构造器
	public CodeBlock() {
		System.out.println("构造器");
	}
  
    //构造代码块
	{
		System.out.println("构造代码块");
	}
	
    //静态构造代码块
    static{
        System.out.println("静态构造代码块");
    }

	public static void main(String[] args) {
        //两次创建对象
		CodeBlock a = new CodeBlock();
		CodeBlock b = new CodeBlock();
	}
}

结果输出:

 八、代码块、构造方法(包含继承关系)的执行顺序

父类的静态成员和代码块——>子类的静态成员和代码块——>父类成员初始化和代码块——>父类构造方法——>子类成员初始化和代码块——>子类构造方法

例1:

//A类
public class A {

static {
    Log.i("HIDETAG", "A静态代码块");
}

private static C c = new C("A静态成员");
private  C c1 = new C("A成员");

{
    Log.i("HIDETAG", "A代码块");
}

static {
    Log.i("HIDETAG", "A静态代码块2");
}

public A() {
    Log.i("HIDETAG", "A构造方法");
}

}
//B类
public class B extends A {

private static C c1 = new C("B静态成员");

{
    Log.i("HIDETAG", "B代码块");
}

private C c = new C("B成员");

static {
    Log.i("HIDETAG", "B静态代码块2");
}

static {
    Log.i("HIDETAG", "B静态代码块");
}

public B() {
    Log.i("HIDETAG", "B构造方法");

}

}
//C类
public class C {
public C(String str) {
    Log.i("HIDETAG", str + "构造方法");
}
}
// 主函数
public static void main(String[] args) {
		B a = new B();
	}

输出结果:

 参考文章:

Java-Tutorial/7、代码块和代码执行顺序.md at master · h2pl/Java-Tutorial · GitHub

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值