九、三个修饰符:abstract、static、final

1.abstract--抽象类、抽象方法

生活中的抽象:从网上搜索动物类,可以具体化子类对象;但是不能具体化动物的对象

程序中的抽象类:有一个类不能够具体化出来对象,这个类就是抽象类
程序中的抽象方法:往往在抽象类中,有这个方法但不能具体实现,这个方法叫做抽象方法

例如: 动物类不能具体化,这个动物类就是抽象类;
       动物类一般都有叫的方法,但不能具体实现,叫的方法我们可以设置为抽象方法; 
       抽象方法用处:作为一个模板,该抽象类的子类必须完成抽象方法的重写

案例: 动物类都有叫的方法,狗类,猫类(子类)完成具体实现
抽取多态: 狗,猫是动物,具备叫的行为      

===========================抽象类概述===========================

//抽象类: 限制该类不能被具体化
//抽象类的好处:1.作为模板使用, 2.更自然的使用多态

//抽象类的特点整理:
//1.抽象类能否实例化对象?    不能
//2.能否有构造方法?                可以有
//3.抽象类中能否有非抽象方法?   可以有
//4.抽象类中能否没有抽象方法?   可以,但一般都要写抽象方法
//5.父类是抽象类,子类必须重写父类方法吗?    不是必须的,可以把自身变为抽象类
//6.有抽象方法的类必须是抽象类吗?  是的

abstract class Animal{
	public Animal() {}  //可以有构造方法,交给子类调用
	
	public void eat(){}  //有非抽象方法
	
	//抽象类中的一些方法,往往有这个方法,但没法实现,这样的方法设置为抽象方法
	//抽象方法作为模板
	public abstract void bark();
	
}

 //The type Dog must implement the inherited abstract method Animal.bark()
//父类为抽象类,子类有两种处理方案
//1.子类要重写父类的方法
//2.将子类也变为抽象类,交给Dog子类去完成
class Dog extends Animal{

	@Override
	public void bark() {
		System.out.println("狗正在旺旺旺地叫...");
	}
	
	public void run() {
		System.out.println("狗正在跑...");
	}
}

abstract class Cat extends Animal{
}

public class Test1 {
	public static void main(String[] args) {
		//Animal animal = new Animal();  //不合适
		
		//抽象类实现多态: 抽象类指向子类对象,即可调用子类重写方法
		//Dog dog = new Dog();  //? 
		Animal animal = new Dog();  //多态,扩展性,维护性更强
		animal.bark();
		//animal.run();  //不能调子类独有方法(当次动物看待,只能调动物的方法或子类重写的)
	}
}
===========================抽象类案例===========================

/*
 案例: 老师开着法拉利牌自行车去上班

改造: 自行车,汽车,地铁,飞机等都是交通工具,都具备运转功能
将交通工具类变为抽象类,通过抽象类实现多态
分析: 交通工具类不能具体化---抽象类
       交通工具的运行功能---有这个功能,但不知道如何实现,抽象方法
 * */

abstract class JiaoTongTool{
	public abstract void run();
}

class Bike extends JiaoTongTool{
	@Override
	public void run() {
		System.out.println("自行车运转: 轮子转啊转,以每小时50公里速度~");
	}
}

class Car extends JiaoTongTool{
	@Override
	public void run() {
		System.out.println("汽车运转:以每小时100公里速度前进~");
	}
	
}

class Teacher{
	//以传参形式通过抽象类实现多态:
	public void start(JiaoTongTool tool) {
		tool.run();  //不要看谁调的,要看谁传的
	}

}

public class Test2 {
	public static void main(String[] args) {
		//抽象类实现多态
		Teacher teacher = new Teacher();
		teacher.start(new Bike());  //1.老师开自行车
		teacher.start(new Car());     //2.老师开汽车

	}
}

2.static--静态成员、类加载

Java中的五大存储区域:
栈、堆、方法区、寄存器区、本地方法区
寄存器区:主要是线程的存储区域
本地防区:第三方语言的存储区域,例如:c/c++

重点分析三大区域:堆,栈,方法区
栈:存局部变量  (引用对象,基本变量)
堆:new对象,成员属性
方法区:class文件,静态区(static修饰),常量池(字符串常量)-往往方法区的东西只有一份

2.1静态属性

=========================成员属性案例=========================
class MyClass{
	int a;  //成员属性
}


public class Test1 {
	public static void main(String[] args) {
		MyClass obj1 = new MyClass();
		MyClass obj2 = new MyClass();
		
		obj1.a = 3;
		obj2.a = 5;
		
		System.out.println(obj1.a+"---"+obj2.a);
	}
}

=======================静态属性案例==========================

//实例属性 VS 静态属性
//实例属性: 在堆区,属于对象,通过对象调用;每个对象独有的一份
//静态属性: 在方法区,属于类,推荐使用类名调用;所有对象共享同一份

class MyC{
	static int a;
}
public class Test2 {
	public static void main(String[] args) {
		MyC obj1 = new MyC();
		MyC obj2 = new MyC();
		
		//The static field MyC.a should be accessed in a static way
		obj1.a = 3;  //MyC.a = 3; 静态属性属于类,推荐通过类名调静态属性
		obj2.a = 5;
		
		System.out.println(obj1.a+"---"+obj2.a);
	}
}

===================静态属性课堂案例====================

//案例: 统计对象new了多少次
//分析: 先编写面向对象; 每new一次,则次数++
class A{
	static int count;  //初始为0
	public A(){
		count++;  //使用静态属性进行统计
	}
}
public class Test3 {
   public static void main(String[] args) {
	  new A();
	  
	  new A();
	  
	  new A();
	  
	  System.out.println("总共new了"+A.count+"次");
   }
}

2.2 静态方法

=====================静态方法应用====================

//问题:在静态方法中,能否使用成员属性;--不能  
      //在成员方法中能否使用静态属性?--能  为什么?

//思考: 函数入口为何要这么设计?    public  static void main()
//public:公开权限,使得外部jvm有权限调用
//static:优先加载,无需new对象,提高性能
//void:  无需反馈结果到jvm 

class MyClass{
	static int a;   //静态属性
	int  b;         //成员属性
	
	//静态方法中不能使用this与super关键字--加载时机问题
	//静态方法可以继承,但不能重写
	public static void test() {  //静态方法
		System.out.println("测试的方法...");
		//加载时机问题,静态区在类加载时就进行加载了,这时还不知道对象属性; 静态区优先对象加载
		//System.out.println(b); 
	}
	
	public void print() {
		System.out.println(a);
	}
}

class Son extends MyClass{
	/*@Override   
	public static void test() {  //静态方法,不能重写
	}*/
}

public class Test1 {
	public static void main(String[] args) {
		//之前方法调用,因为是调当前类的方法,所有省略了类名的调用
		System.out.println(add(1,2));  //调当前类的方法  等价Test1.add(1,2);
		
		//The static method add(int, int) from the type Test1 should be accessed in a static way
		System.out.println(new Test1().add(3, 5)); //可以通过对象调静态方法,但是不推荐
		
		//调用系统提供的静态方法
		int[] a = {1,2,3};
		System.out.println(Arrays.toString(a)); //调其他类的方法: 类名.方法
		
		MyClass.test();  //调用自定义类的静态方法
		
		//new Son().test();  //静态方法具有继承性
	}

	//静态方法:属于类,推荐使用类名调用
	public static int add(int a, int b) {
		return a+b;
	}
}
=====================静态的应用场景====================

//静态属性和静态方法的应用场景:
//静态属性: 一般作为状态值去使用(往往变量全大写)---固定值,不用更改,直接使用-做逻辑判断
//状态值的好处: 可读性更强 ,可维护性更强(变更数值了,不用每个地方都去改)

//静态方法:作为工具类来使用(工具类:统一供外部调用的公共类;例如:Arrays,所有数组操作的静态方法都放到该类)

class MyC{
	static int SEX_MAN = 11;  //代表男
	static int SEX_WOMAN = 10;  //代表女
}

public class Test2 {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		System.out.print("请输入性别:1.男性,0.女性:  ");
		int sex = sc.nextInt();
		if(sex==MyC.SEX_MAN) {
			System.out.println("你输入的是男性");
		}else if(sex==MyC.SEX_WOMAN) {
			System.out.println("你输入的是女性");
		}
		
		
		/*
		if(sex==MyC.SEX_MAN) {
			System.out.println("你输入的是男性");
		}else if(sex==MyC.SEX_WOMAN) {
			System.out.println("你输入的是女性");
		}*/
	    	
	}
}

2.3 动态代码块与类加载

=====================动态代码块案例====================
//动态代码块: 就是类中的一块区域,只要在类中加入{},就是一个代码块;
//通过实例化对象可以触发到动态代码块
//执行流程:
//成员属性>动态代码块>构造方法
//作用: 给属性赋予初始值

//类加载过程:
//jvm根据classpath查找class文件,并将class文件中的所有信息(包名,类名,对象,属性,方法等)加载到内存中
//需要在入口main中触发执行类加载

class MyClass{
	String a = "成员属性";
	static String b = "静态属性";
	
	{
		System.out.println(a);
		System.out.println("动态代码块");
	}
	
	public MyClass() {
		System.out.println("构造方法");
	}
	
	public static void show() {
		System.out.println("调用静态方法");
	}
}

class Son extends MyClass{
	
}
public class Test1 {
	public static void main(String[] args) throws ClassNotFoundException {
		//new MyClass();  //实例化对象触发
		//new Son();        //实例化子类对象
		//System.out.println(MyClass.b);  //静态属性触发类加载
		//MyClass.show();   //使用静态方法触发类加载
		Class.forName("com.qf.c_statickuai.MyClass");  //加入全限定名,触发类加载-反射后面学
	}
}
=====================静态代码块的执行====================
//静态代码块的执行:
//先执行静态属性>静态代码块(通过反射触发)
class MyC{
	static String a = "静态属性";
	//静态代码块
	static {
		System.out.println(a);
		System.out.println("静态代码块");
	}
	
}

public class Test2 {
	public static void main(String[] args) throws ClassNotFoundException {
		Class.forName("com.qf.c_statickuai.MyC");
	}
}
=====================动态代码块与静态代码块====================
//对象的执行过程(动态代码块+静态代码块):
//规则: 先静态,后动态     静态属性->静态代码块->成员属性->动态代码块->构造方法
//再new一个对象: 再执行一次,成员属性->动态代码块->构造方法
//结论:static与对象无关,静态代码块只加载一次,优先于非静态的执行
class Super{
	static String a = "父类静态属性";
	String  b = "父类成员属性";
	static {
		System.out.println(a);
		System.out.println("父类静态代码块");
	}
	
	{
		System.out.println(b);
		System.out.println("父类动态代码块");
	}
	
	public Super() {
		System.out.println("构造方法");
	}
}

public class Test1 {
	public static void main(String[] args) {
		new Super();  //实例化当前类的构造方法    先静态,后动态
		System.out.println("===============");
		new Super();  //再new一个对象
	}
}
=====================子类的实例化过程====================
//案例:子类继承Super类,观察子类实例化过程
//规则: 先父类,再子类,先静态,后动态

//执行流程:父类静态属性>父类静态代码块>子类静态属性>子类静态代码块>父类成员属性>父类动态代码块
      // 父类构造方法>子类成员属性>子类动态代码块>子类构造方法
class Son extends Super{
	static String a = "子类静态属性";
	String b = "子类成员属性";
	{
		System.out.println(b);
		System.out.println("子类动态代码块");
	}
	
	static {
		System.out.println(a);
		System.out.println("子类静态代码块");
	}
	
	public Son() {
		System.out.println("子类构造方法");
	}
}

public class Test2 {
	public static void main(String[] args) {
		 new Son();
	}
}

3. final--最终类、方法、常量

final:表示最终的,可以修饰类,方法,属性
修饰类:最终类(太监类),被final修饰的类不能有子类
修饰方法: 该方法不能被重写
修饰属性: 变量变为了常量,往往在静态属性中final与static配合使用(状态值)-静态常量

//final修饰类,该类不能有子类
/*final*/ class Super{
	//静态常量必须初始化时要赋值
	//静态常量赋值时机:1.初始时赋值   2.静态代码块
	public final static int COUNT=1;  //状态值往往是不能被改变的,+final修饰则变为了常量
	/*static {
		COUNT = 2;
	}*/

	//成员常量必须初始化时要赋值
	//成员常量赋值时机: 1. 初始时赋值   2.动态代码块   3.构造方法
	public final int d=1;
	/*{
		d = 3;
	}*/
	
	/*public Super() {
		d = 5;
	}*/
	
	
	
	//final修饰方法,该方法不能被重写
	public /*final*/ void test(){
		
	}
}

//The type Son cannot subclass the final class Super
class Son extends Super{
	int b;
	@Override
	//Cannot override the final method from Super
	public void test(){
		
	}
}

public class Test1 {
	public static void main(String[] args) {
		//Super.COUNT = 5;  //The final field Super.COUNT cannot be assigned
		
		//基本类型的局部变量中的final修饰: 该变量值不能改变
		final int a = 3;
		//a = 5;  不能改变
		
		//引用类型的局部变量中加final修饰: 该变量地址不能改变,与属性值无关
		final Son son = new Son();
		//son.b = 6;
		//son = new Son();  //地址不能改变
		
		//数组也是引用类型,修饰数组后,地址不能变,里面的元素值可以变
		final int[] c = {1,2,3};
		//c = new int[]{4,5};  //地址不能改变
		c[0] = 6;
		
	}
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值