当前位置:首页 » 《休闲阅读》 » 正文

JavaSE02_面向对象03_类的五大成员之构造器&代码块_AE86啊 怎样的博客

3 人参与  2022年02月05日 08:53  分类 : 《休闲阅读》  评论

点击全文阅读


类的成员之三:构造器

类的两个核心成员: 属性 提供数据,方法 提供操作;
剩下的三个成员都是辅助作用;
构造器代码块都是对属性进行初始化的;
内部类其实和属性是一个性质,也是属于类的数据部分

1、格式

[访问控制修饰符]  类名(){
}
或
[访问控制修饰符]  类名(形参列表){
}

2、作用

(1)与new一起使用创建对象
(2)为对象属性进行初始化

3、特点

(1)构造器的名称必须与类名相同
(2)构造器没有返回值类型
(3)若一个类中没有显式的提供任何构造器时,系统会为其提供一个默认的无参构造器。
(4)若一个类中显式声明了任何构造器,那么系统将不再为其提供默认的无参构造器。
(5)一个类中可以重载多个构造器(重载的多个构造器名称都与类名相同,形参列表必须各不相同)

4、为属性赋初始值的方式

(1)默认值
(2)显式初始化
(3)构造器初始化
注意:

  • 如果三者同时存在,那么按照(1)(2)(3)的顺序进行
  • 显示初始化包含 直接给属性赋值通过代码块给属性赋值 二者按照书写顺序进行,优先级相同

this关键字

this表示当前对象
(1)在方法内部使用,即表示调用该方法的对象
(2)在构造方法中使用,即表示正在初始化的对象

用法:
1. this.属性
(1)当构造器或方法中有局部变量与实例变量同名时,用于区分局部变量和实例变量。
格式:this.属性
(2)当构造器或方法中没有局部变量与实例变量同名时,可以不加this.
2. this.方法
表示调用当前对象的其他方法,通常情况下,省略this.
3. this()或this(实参列表)
用于调用本类的其他构造方法,必须写在构造器的首行,要避免递归调用
格式:this(); 或 this(实参列表);

补充:使用this访问属性和方法时,如果在本类中未找到,会从父类中查找(从父类继承的当做自己的一样使用)。

static关键字

1.为什么要使用static关键字

当我们编写一个类时,其实就是在描述其对象的属性和行为,而并没有产生实质上的对象,只有通过new关键字才会产生出对象,这时系统才会分配内存空间给对象,其方法才可以供外部调用。我们有时候希望无论是否产生了对象或无论产生了多少对象的情况下,某些特定的数据在内存空间里只有一份,例如所有的中国人都有个国家名称,每一个中国人都共享这个国家名称,不必在每一个中国人的实例对象中都单独分配一个用于代表国家名称的变量。

2.类属性、类方法的设计思想

类属性(类变量)作为该类各个对象之间共享的变量。在设计类时,分析哪些类属性不因对象的不同而改变,将这些属性设置为类属性。相应的方法设置为类方法。
如果方法与调用者无关,则这样的方法通常被声明为类方法,由于不需要创建对象就可以调用类方法,从而简化了方法的调用。

3.static修饰的范围

修饰类的内部成员:
可用static修饰属性、方法、代码块、内部类

(1)类变量(class Variable)

当某个属性的值是所有对象共享的,那么这样的属性应该声明为静态的,这样的属性我们称为类变量。

类变量具备以下特点:
1.随着类的初始化而初始化,优先于实例对象的创建
2.修饰的成员,被所有对象所共享
3.访问权限允许时,可不创建对象,直接“类名.xx”调用
4.类变量的值存储在方法区
5.类变量的get/set方法也是静态的
在这里插入图片描述

(2)类方法(class Method)

当方法的功能实现、调用和该类的对象无关时,我们可以把这样的方法声明为static,我们称为静态方法。

  • static修饰的方法,只要访问权限允许,可以通过"类名.方法"访问,因此static的方法也称为类方法。
  • 在static方法内部只能访问类变量与类方法(static属性和方法),不能访问类的实例变量和成员方法(非static属性和方法)。
  • static方法内部不能有this和super。
    如果在静态方法中有局部变量与类变量重名,可以使用“本类名.xxx”
    如果在静态方法中想要访问父类的静态成员,可以使用“父类名.xxx”
    
  • static修饰的方法不能被重写,或者说不会被覆盖
因为静态方法是类方法,是属于类的,和对象无关

(3)代码块

(4)内部类

4、静态与非静态的访问原则(☆)

(1)同一个类中:
静态成员中不能访问非静态的成员
非静态成员中可以访问静态成员
(2)不同类中:
访问其他类的非静态成员必须使用“对象.非静态成员”的格式
访问其他类的静态成员建议使用“类名.静态成员”的格式,也可以使用“对象.静态成员”

类的成员之四:代码块

代码块的作用:一般来说是用于类或实例成员变量的初始化;
代码块有两种:分为静态代码块和非静态代码块(构造代码块)

1、静态代码块

(1)可以为类变量(静态的属性)初始化
(2)随着类的初始化而初始化,只执行一次
(3)如果子类初始化时,它的父类没有初始化会先初始化父类
(4)在静态代码块中不能访问非静态成员(属性、方法、内部类)
(5)在静态代码块中不能使用this和super关键字

如果有重名问题,需要访问本类或父类的静态成员,那么可以使用“本类名.xx”、“父类名.xx”
如果没有重名问题,直接访问即可。

2、非静态代码块(构造块)

(1)可以为实例变量(非静态的属性)初始化
(2)随着对象的创建而初始化,每创建一个对象,就执行一次
(3)创建子类对象时,需要先为从父类继承的属性进行初始化,所以会导致父类的构造块和构造器先执行
(4)本类的非静态代码块优先于构造器执行

3、初始化顺序

(1)类初始化
如果不需要创建对象,那么仅仅是类初始化
在这里插入图片描述

(2)创建对象
如果要创建对象,那么要先看类是否之前初始化过,如果没有,那么要先初始化类,然后才能创建对象。
在这里插入图片描述

package _06_Object_static_final;

public class _static {
    public static void main(String[] args) {
        Demo d = new Demo();
    }
}


class Demo{
    {
        System.out.println("(1) Demo的非静态代码块1");
    }
    static {
        System.out.println("(2) Demo的静态代码块1");
    }
    private static String info = assign();
    private String message = getMessage();

    static{
        System.out.println("(3) Demo静态代码块2");
    }
    {
        System.out.println("(4) Demo非静态代码块2");
    }

    public Demo(){
        System.out.println("(5) Demo 无参构造");
    }

    public static String assign(){
        System.out.println("(6) assign()方法");
        return "hello";
    }

    public String getMessage(){
        System.out.println("(7) getMessage()方法");
        return "hello";
    }

}
类初始化 先完成  再实例初始化

(2) Demo的静态代码块1
(6) assign()方法
(3) Demo静态代码块2
(1) Demo的非静态代码块1
(7) getMessage()方法
(4) Demo非静态代码块2
(5) Demo 无参构造

Process finished with exit code 0

(3)总结升华(☆☆☆)
1.类初始化方法<clinit>()

  • 一个类只有一个,由编译器编译生成,由两部分代码组成:
1.静态变量的显示赋值代码
2.静态代码块的代码
  • 每一个类的<clinit>()只会执行一次,且在第一次使用这个类的时候执行,即在类的初始化的时候执行。

  • 这两个部分的执行顺序是谁在前先执行谁。

  • 执行子类的<clinit>()方法时,如果父类没有初始化,会先执行父类的<clinit>方法;如果初始化过了父类,就不用初始化父类了。一个类只初始化一次。


2.实例初始化方法<init>()或者<init>(形参列表)

  • 由编译器生成,三部分代码组成:
 成员变量的显示赋值代码
 非静态代码块
 构造器
  • 有几个构造器就有几个实例初始化方法(实力初始化方法的参数列表对应构造器的参数列表)

不管是类变量还是实例变量都有默认值,再用或初始化之前,就有默认值。

4、初始化顺序案例

(1)父类<clinit> -> 子类<clint> -> 父类<init>() -> 子类<init>()

package com.atguigu.exer1;

public class TestStaticExer1 {
	public static void main(String[] args) {
		Son son = new Son();
	}
}
class Father{
	static{
		System.out.println("(1)父类的静态代码块");
	}
	{
		System.out.println("(2)父类的非静态代码块");
	}
	Father(){
		System.out.println("(3)父类的无参构造");
	}
}
class Son extends Father{
	static{
		System.out.println("(4)子类的静态代码块");
	}
	{
		System.out.println("(5)子类的非静态代码块");
	}
	Son(){
		System.out.println("(6)子类的无参构造");
	}
}	
(1)(4)(2)(3)(5)(6)

(2)main方法所在类最先加载,且类加载只进行一次。

package _06_Object_static_final;

public class _static03 {
    static{
        System.out.println("static03的静态代码块");
    }

    public static void main(String[] args) {
        mClass.test();
        mClass.test();
        mClass.test();
    }
}

class mClass{
    static{
        System.out.println("mClass的静态代码块");
    }
    public static void test(){
        System.out.println("静态方法");
    }
}
static03的静态代码块
mClass的静态代码块
静态方法
静态方法
静态方法

Process finished with exit code 0

(3)子类加载先加载父类,父类家加载了就不再加载了

package _06_Object_static_final;

/**
 *  父类先加载于子类
 */
public class _static04 {
    public static void main(String[] args) {
        Son s  = new Son();
    }

}

class Farther{
    static{
        System.out.println("(1) 父类静态代码块");
    }

}
class Son extends Farther{
    static{
        System.out.println("(2) 子类静态代码块");
    }
}
(1) 父类静态代码块
(2) 子类静态代码块

Process finished with exit code 0

(4)静态方法不存在重写和动态绑定

package _06_Object_static_final;

/**
 *  父类先加载于子类, 静态方法不存在重写和动态绑定
 */
public class _static04 {
    public static void main(String[] args) {
       
        Farther f = new Son();
        System.out.println("---------");
        f.assign(); //Farther.assign()
    }

}

class Farther{
    private static String info = assign();
    static{
        System.out.println("(1) 父类静态代码块");
    }
    public static String assign(){
        System.out.println("(3)  assign()方法");
        return "farther";
    }

}
class Son extends Farther{
    private static String info = assign();
    static{
        System.out.println("(2) 子类静态代码块");
    }

    public static String assign(){
        System.out.println("(4)  assign()方法");
        return "Son";
    }
}
(3)  assign()方法
(1) 父类静态代码块
(4)  assign()方法
(2) 子类静态代码块
---------
(3)  assign()方法

其他关键字

final关键字

在Java中声明类、属性和方法时,可使用关键字final来修饰,表示“最终”。

  • final标记的类(太监类)不能被继承。提高安全性,提高程序的可读性。
    String类、System类、StringBuffer类
  • final标记的方法不能被子类重写。
    Object类中的getClass()。
  • final标记的变量(成员变量或局部变量)即称为常量,名称大写。
  • final标记的成员变量在使用之前必须手动赋值,赋值的时机:声明的时候 或 在构造方法中 或 代码块中显式赋值; 且只能赋值一次
package _06_Object;

public class _final {
    final int i = 0;
    final int b;
    {
        b = 1;
    }
    final int c;
    public _final(int c){
        this.c = c;
    }

}

native关键字

使用native关键字说明这个方法是原生函数,也就是这个方法是用C/C++等非Java语言实现的,并且被编译成了DLL,由java去调用。
(1)为什么要用native方法
java使用起来非常方便,然而有些层次的任务用java实现起来不容易,或者我们对程序的效率很在意时,问题就来了。例如:有时java应用需要与java外面的环境交互。这是本地方法存在的主要原因,你可以想想java需要与一些底层系统如操作系统或某些硬件交换信息时的情况。本地方法正是这样一种交流机制:它为我们提供了一个非常简洁的接口,而且我们无需去了解java应用之外的繁琐的细节。
(2)native声明的方法,对于调用者,可以当做和其他Java方法一样使用

  • 一个native method方法可以返回任何java类型,包括非基本类型,而且同样可以进行异常控制。
    native method的存在并不会对其他类调用这些本地方法产生任何影响,实际上调用这些方法的其他类甚至不知道它所调用的是一个本地方法。JVM将控制调用本地方法的所有细节。
  • 如果一个含有本地方法的类被继承,子类会继承这个本地方法并且可以用java语言重写这个方法(如果需要的话)。

关于关键字常见问题

1、构造器只能有访问控制修饰符
2、外部类不能使用static修饰,可以使用final修饰
3、属性可以同时使用static和final修饰,叫做全局常量
4、方法可以同时使用static和final修饰,都不能被重写
5、局部变量只能使用final修饰
6、代码块只能使用static修饰

类的成员之五:内部类Inner Class

1、为什么要有内部类

1.内部类场景
当一个事物的内部,还有一个部分需要一个完整的结构进行描述,而这个内部的完整的结构又只为外部事物提供服务,那么整个内部的完整结构最好使用内部类。
2.内部类特点
声明为内部类可以直接使用访问外部类的所有的成员,包括私有的.

3.源代码示例:
JRE核心类库集合的迭代器大量使用内部类;每一个集合实现类都有个迭代器内部类

2、内部类的分类

(1) 静态内部类
(2)非静态内部类:

  • 成员内部类
  • 局部内部类
  • 匿名内部类

3、成员内部类

(1)如何声明成员内部类

声明的位置:在类中方法外
格式如下:

[修饰符] class 外部类{
 	[修饰符] class 成员内部类{
 	}
 }

(2)成员内部类的特点

  • 内部类仍然是一个独立的类,在编译之后内部类会被编译成独立的.class文件,但是前面冠以外部类的类名和$符号。例如:Outer$Inner.class
  • 成员内部类也是外部类的一个成员,可以使用所有权限修饰符 public,protected,default,private
  • 成员内部类还可以使用final和abstract修饰
  • 成员内部类中不可以包含静态成员
  • 成员内部类可以直接使用外部类的所有成员,包括私有的。
  • 如果成员内部类有与外部类的非静态属性重名时,可以通过“外部类名.this.属性”进行区别,如果与外部类的静态属性重名时,可以通过“外部类名.类变量”进行区别

(3)如何使用成员内部类

1.在外部类中使用成员内部类

  • 在外部类的静态成员中不能使用非静态的成员内部类
  • 在外部类的非静态成员中,直接创建内部类的对象来访问内部类的属性与方法。此时把它当做一个普通的类即可

2.在外部类的外面使用成员内部类

  • 需要外部类的对象才能创建成员内部类的对象
package com.innerclass.member;

public class TestMemberClass {

	public static void main(String[] args) {
		Outer out = new Outer();
		out.outerMethod();
		
		Outer.Inner oi = out.new Inner();
		oi.innerMethod();
		
		Outer.Inner obj = out.getInner();
		obj.innerMethod();
	}

}
class Outer{
	private int value = 5;
	public static void outerStaticMethod(){
		/*Inner in = new Inner();//错误
		in.innerMethod();*/
	}
	public void outerMethod(){
		System.out.println("外部类的方法");
		/*Inner in = new Inner();//可以
		in.innerMethod();*/
	}
	class Inner{
		public void innerMethod(){
			System.out.println("内部类的方法");
			System.out.println("内部类的方法访问外部类的私有成员:"+value);
		}
	}
	//通过外部类的某个方法返回内部类的对象
	public Inner getInner(){
		return new Inner();
	}
}

4、静态内部类

(1)如何声明静态内部类

声明的位置:在类中方法外
格式如下:

[修饰符] class 外部类{
 	[修饰符] static class 静态内部类{
 	}
 }

(2)什么时候声明静态内部类

  • 当内部类需要包含静态成员时
  • 当想要在外部类的静态成员部分使用内部类时

(3)静态内部类的特点

  • 内部类仍然是一个独立的类,在编译之后内部类会被编译成独立的.class文件,但是前面冠以外部类的类名和$符号。例如:Outer$Inner.class
  • 静态内部类可以使用修饰符public,protected,default,private
  • 静态内部类还可以使用final和abstract修饰
  • 静态内部类中可以包含静态成员
  • 静态内部类可以直接使用外部类的静态成员,包括私有的。但不能使用外部类的非静态成员。
  • 静态内部类中有与外部类的静态属性重名时,如果要表示是外部类的属性,那么用“外部类名.属性”

(4)如何使用静态内部类

  • 在外部类中使用静态内部类:就和使用其他普通类一样
    • 在外部类的静态成员中
    • 在外部类的非静态成员中
  • 在外部类的外面使用成员内部类:
    • 使用静态内部类的静态成员:外部类名.静态内部类名.静态内部类的静态成员
    • 使用静态内部类的非静态成员:外部类名.静态内部类名 obj = new 外部类名.静态内部类名();
      obj.静态内部类的非静态成员
package com.innerclass.staticinner;

public class TestStaticInnerClass {

	public static void main(String[] args) {
		Outer.StaticInnerClass.innerStaticMethod();
		Outer.StaticInnerClass os = new Outer.StaticInnerClass();
		os.innerMethod();
	}

}
class Outer{
	public static void outerStaticMethod(){
		StaticInnerClass.innerStaticMethod();
		StaticInnerClass si = new StaticInnerClass();
		si.innerMethod();
	}
	public static void outerMethod(){
		StaticInnerClass.innerStaticMethod();
		StaticInnerClass si = new StaticInnerClass();
		si.innerMethod();
	}
	static class StaticInnerClass{
		public static void innerStaticMethod(){
			System.out.println("内部类的静态方法");
		}
		public void innerMethod(){
			System.out.println("内部类的非静态方法");
		}
	}
}

5、局部内部类

(1)如何声明局部内部类

声明的位置:在外部类的方法或代码块中
格式如下:

[修饰符]  class 外部类{
 	方法{
			class 局部内部类{
				}
		}
}

(2)局部内部类的特点

  • 内部类仍然是一个独立的类,在编译之后内部类会被编译成独立的.class文件“外部类的类名$数字编号内部类名.class”。
  • 局部内部类和局部变量地位类似,不能使用public,protected,private,static这些成员修饰符,但是可以使用abstract或final
  • 局部内部类不能使用static修饰,因此也不能包含静态成员。
  • 只能在声明它的方法或代码块中使用,而且是先声明后使用。除此之外的任何地方都不能使用该类,因为作用域的问题。
  • 局部内部类可以使用外部类的成员,包括私有的。但是是否可以使用外部类的非静态成员要看所在方法是否是非静态的。
  • 局部内部类可以使用外部方法的局部变量,但是必须是final的。由局部内部类和局部变量的生命周期不同所致。

(3)如何使用局部内部类

  • 只能在声明它的方法或代码块中使用,而且是先声明后使用。除此之外的任何地方都不能使用该类。
  • 但是它的对象可以通过外部方法的返回值返回使用,返回值类型只能是局部内部类的父类或父接口类型。
package com.innerclass.local;

public class TestLocalInnerClass {

	public static void main(String[] args) {
		Outer out = new Outer();
		Object obj = out.outerMethod();
		System.out.println(obj);
	}

}
class Outer{
	int value = 5;
	public Object outerMethod(){
		final int localValue = 10;
		class LocalInnerClass{
			public void innerMethod(){
				System.out.println("局部内部类的方法");
				System.out.println("局部内部类的方法可以使用外部类的成员:"+value);
				System.out.println("局部内部类的方法可以使用外部类的局部变量:"+localValue);
			}
		}
		//先声明后使用
		LocalInnerClass li = new LocalInnerClass();
		li.innerMethod();
		return li;
	}
}

6、匿名内部类

(1)如何声明匿名内部类

声明的位置:任何可以创建对象的语句中
格式如下:

new 父类/父接口(){
	....
}

意思是创造一个实现(继承)了接口(父类)的类的对象。

(2)匿名内部类的特点

  • 匿名内部类是类,它编译后的字节码文件名是:外部类名$数字编号.class
  • 匿名内部类必须继承父类或实现接口
  • 匿名内部类只能有一个对象
  • 匿名内部类对象只能使用多态形式引用
  • 匿名内部类是特殊的局部内部类,局部内部类的所有限制对它都适用

(3)如何使用匿名内部类

三种使用方法:

  • 继承式
  • 接口式
  • 参数式
package com.innerclass.anonymous;

import java.util.Arrays;
import java.util.Comparator;

public class TestAnonymous {

	public static void main(String[] args) {
		//继承式
		Car car = new Car(250){
			public void run(){
				System.out.println("改进型:" + getSpeed());
			}
		};
		
		Car[] cars = new Car[3];
		cars[0] = car;
		cars[1] = new Car(120);
		cars[2] = new Car(140);
		
		for (Car c : cars) {
			c.run();
		}
		
		//接口式
		Comparator com = new Comparator() {

			@Override
			public int compare(Object o1, Object o2) {
				Car c1= (Car) o1;
				Car c2= (Car) o2;
				return c1.getSpeed() - c2.getSpeed();
			}
		};
		
		Arrays.sort(cars,com);
		
		//参数式
		Arrays.sort(cars,new Comparator() {

			@Override
			public int compare(Object o1, Object o2) {
				Car c1= (Car) o1;
				Car c2= (Car) o2;
				return c1.getSpeed() - c2.getSpeed();
			}
		});
		
		
		for (Car c : cars) {
			c.run();
		}
	}

}
class Car{
	private int speed;
	
	public Car() {
		super();
	}

	public Car(int speed) {
		super();
		this.speed = speed;
	}

	public int getSpeed() {
		return speed;
	}

	public void setSpeed(int speed) {
		this.speed = speed;
	}

	public void run(){
		System.out.println("标准发动机助跑" + speed);
	}
}

点击全文阅读


本文链接:http://zhangshiyu.com/post/34290.html

部类  静态  方法  
<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1