重载方法
使用同样的命名来定义不同的方法,只要参数不同(即签名不同)。
Java编译器根据方法签名决定使用哪个方法:
public class Main {
public static void main(String[] args) {
initData(100, 10);
initData(3.14, 2.9);
}
// 整数类型
public static void initData(int x, int y) {
System.out.println("x: " + x);
System.out.println("y: " + y);
}
// 浮点数类型
private static void initData(double x, double y) {
System.out.println("x: " + x);
System.out.println("y: " + y);
}
}
静态方法和实例方法
静态方法可使用"类名.方法名"调用,或"对象名.方法名"调用,(调用方式同Python相同)
实例方法可使用"对象名.方法名"调用
代码块
代码块就是用大括号({})将多行代码封装在一起,形成一个独立的数据体,用于实现特定的算法。
- 普通代码块
方法名后面用{}括起来的代码段:
public class Test {
public void test(){
System.out.println("普通代码块");
}
}
- 静态代码块
用static修饰的用{}括起来的代码段,它的主要目的就是对静态属性进行初始化
public class Main {
static int cnt = 6;
static {
cnt += 9;
}
public static void main(String[] args) {
System.out.println(cnt); // 显示5
}
static {
cnt /= 3;
}
}
静态代码块的注意:
1、它是随着类的加载而执行,只执行一次,并优先于主函数。具体说,静态代码块是由类调用的。类调用时,先执行静态代码块,然后才执行主函数的。
2、静态代码块其实就是给类初始化的,而构造代码块是给对象初始化的。
3、码块中的变量是局部变量,与普通函数中的局部变量性质没有区别。
4、一个类中可以有多个静态代码块
-
同步代码块
使用 synchronized 关键字修饰,并使用“{}”括起来的代码片段,它表示同一时间只能有一个线程进入到该方法块中,是一种多线程保护机制 -
构造代码块
在类中直接定义没有任何修饰符、前缀、后缀的代码块即为构造代码块.
编译器会将代码块按照他们的顺序(假如有多个代码块)插入到所有的构造函数的最前端,这样就能保证不管调用哪个构造函数都会执行所有的构造代码块
只有实例化对象时直接调用的构造函数才会执行一次构造代码块:
public class Main {
{ // 构造代码块
System.out.println("执行构造代码块1...");
}
public Main(){
this("1245");
System.out.println("执行无参构造函数...");
}
public Main(String id){
System.out.println("执行有参构造函数...");
}
public static void main(String[] args) {
Main cc = new Main();
Main cc2 = new Main("1234");
}
{ // 构造代码块
System.out.println("执行构造代码块2...");
}
}
/* output:
执行构造代码块1...
执行构造代码块2...
执行有参构造函数...
执行无参构造函数...
执行构造代码块1...
执行构造代码块2...
执行有参构造函数...
*/
构造代码块使用场景:
1、 初始化实例变量:多个函数都需要初始化实例变量时,应将该变量放入构造代码块
2、初始化实例环境:将创建对象的存在环境的代码封装到构造代码块,提升构造函数的可读性
关于构造代码块,以下几点要注意:
1、构造代码块的作用是给对象进行初始化。
2、对象一建立就运行构造代码块了,而且优先于构造函数执行。这里要强调一下,有对象建立,才会运行构造代码块,类不能调用构造代码块的,而且构造代码块与构造函数的执行顺序是前者先于后者执行。
3、构造代码块与构造函数的区别是:构造代码块是给所有对象进行统一初始化,而构造函数是给对应的对象初始化,因为构造函数是可以多个的,运行哪个构造函数就会建立什么样的对象,但无论建立哪个对象,都会先执行相同的构造代码块。也就是说,构造代码块中定义的是不同对象共性的初始化内容。
Java类初始化顺序
顺序: 静态代码块 > 构造代码块 > 构造函数
public class Main {
public static void main(String[] args) {
new InitialOrderTest();
}
}
class InitialOrderTest {
/* 静态变量 */
public static String staticField = "静态变量";
/* 实例变量 */
public String field = "实例变量";
/* 静态初始化块 */
static {
System.out.println( staticField );
System.out.println( "静态初始化块" );
}
/* 构造代码块 */
{
System.out.println( field );
System.out.println( "初始化块" );
}
/* 构造方法 */
public InitialOrderTest()
{
System.out.println( "构造方法" );
}
}
/* output
静态变量
静态初始化块
实例变量
初始化块
构造方法
*/
方法重写
子类从父类中继承方法,而子类需要修改父类中定义的方法的实现,这就是方法重写
public class Main {
public static void main(String[] args) {
SubBase cc = new SubBase();
cc.f();
}
}
class Base {
public void f() {
System.out.println("Base");
}
}
class SubBase extends Base {
public void f() { // 子类重写父类的f方法,父类的方法被屏蔽掉
System.out.println("SubBase");
}
}
注意:
1、仅当实例方法是可访问时,才能被重写。因为private方法在类外是不能访问,不能继承的,所有不可能被覆盖。
2、静态方法可被继承,但不能被覆盖。父类定义的静态方法在子类被重新定义为新静态方法,父类的静态方法将被隐藏,使用"父类名.静态方法名"可调用隐藏的静态方法。
throw : 该关键字用于主动抛出异常
try … catch: 捕获后处理异常
throws: 声明方法可能抛出异常,使用方式"throws 异常类" ,主要是告诉其它程序方法可能会抛出的异常
1、throws的作用,声明一个函数可能会产生异常,但是我们在这个函数里面不处理, 而且由调用这个函数的对象进行异常try…catch…finally…
2、throw抛出的非运行时异常(继承自Exception的异常)需要throws声明在方法上
3、throw抛出运行时异常(继承自RuntimeException的异常)不需要throws声明在方法上
异常处理
- 形式:
try {
...
new ArithmeticException("Divisor cannot be zero")// throw语句直接抛出异常,或调用一个可能抛出异常的方法
...
}
catch (ArithmeticException ex) { /*type:可捕获的异常类型;ex:保存异常抛出后的值*/
// 执行异常处理代码
}
- 异常处理的优势:
将检测错误(由被调用的方法完成)从处理错误(由调用方法完成)中分离处理:方法抛出一个异常,由由调用者决定是否终止程序。
- 注意:
1、没有处理的异常会沿着方法调用链向上传递,最终没有被捕获则会终止程序
2、父类中没有声明异常的方法,不能在子类中对其进行继承来声明异常