java面向对象-其它关键字

35 阅读7分钟

其它关键字

关键字static(基于生命周期的角度去考虑就一清二楚了)

如果想让一个类的所有实例共享数据,就用类变量!

static 关键字的内存分析

类方法(静态方法)

package com.atguigu.java1;
/*
 * static关键字的使用
 * 
 * 1.static:静态的
 * 2.static可以用来修饰:属性、方法、代码块、内部类
 * 
 * 3.使用static修饰属性:静态变量(或类变量)
 * 		3.1 属性,按是否使用static修饰,又分为:静态属性  vs 非静态属性(实例变量)
 * 		 实例变量:我们创建了类的多个对象,每个对象都独立的拥有一套类中的非静态属性。当修改其中一个对象中的非静态属性时,不会导致其他对象中同样的属性值的修改。
 *       静态变量:我们创建了类的多个对象,多个对象共享同一个静态变量。当通过某一个对象修改静态变量时,会导致其他对象调用此静态变量时,是修改过了的。
 * 		3.2 static修饰属性的其他说明:
 * 			① 静态变量随着类的加载而加载。可以通过"类.静态变量"的方式进行调用
 *          ② 静态变量的加载要早于对象的创建。
 *          ③ 由于类只会加载一次,则静态变量在内存中也只会存在一份:存在方法区的静态域中。
 *          ④		类变量	实例变量
 *          类		yes		no
 *          对象	yes		yes
 *          
 *      3.3 静态属性举例:System.out; Math.PI;
 * 
 * 4.使用static修饰方法:静态方法
 * 		① 随着类的加载而加载,可以通过"类.静态方法"的方式进行调用
 * 		②			静态方法	非静态方法
 *          类		yes		no
 *          对象	yes		yes
 * 		③ 静态方法中,只能调用静态的方法或属性
 *        非静态方法中,既可以调用非静态的方法或属性,也可以调用静态的方法或属性
 * 
 * 5. static注意点:
 *    5.1 在静态的方法内,不能使用this关键字、super关键字
 *    5.2 关于静态属性和静态方法的使用,大家都从生命周期的角度去理解。
 *    
 * 6. 开发中,如何确定一个属性是否要声明为static的?
 * 		> 属性是可以被多个对象所共享的,不会随着对象的不同而不同的。
 * 		> 类中的常量也常常声明为static
 * 
 *    开发中,如何确定一个方法是否要声明为static的?
 *    	> 操作静态属性的方法,通常设置为static的
 *      > 工具类中的方法,习惯上声明为static的。 比如:Math、Arrays、Collections
 */
public class StaticTest {
	public static void main(String[] args) {
		
		Chinese.nation = "中国";
		
		
		Chinese c1 = new Chinese();
		c1.name = "姚明";
		c1.age = 40;
		c1.nation = "CHN";
		
		Chinese c2 = new Chinese();
		c2.name = "马龙";
		c2.age = 30;
		c2.nation = "CHINA";
		
		System.out.println(c1.nation);
		
		//编译不通过
//		Chinese.name = "张继科";
		
		
		c1.eat();
		
		Chinese.show();
		//编译不通过
//		Chinese.eat();
//		Chinese.info();
	}
}
//中国人
class Chinese{
	
	String name;
	int age;
	static String nation;
	
	
	public void eat(){
		System.out.println("中国人吃中餐");
		//调用非静态结构
		this.info();
		System.out.println("name :" +name);
		//调用静态结构
		walk();
		System.out.println("nation : " + nation);
	}
	
	public static void show(){
		System.out.println("我是一个中国人!");
		//不能调用非静态的结构
//		eat();
//		name = "Tom";
		//可以调用静态的结构
		System.out.println(Chinese.nation);
		walk();
	}
	
	public void info(){
		System.out.println("name :" + name +",age : " + age);
	}
	
	public static void walk(){
		
	}
}

单例 (Singleton)设计模式

所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法。

如果我们要让类在一个虚拟机中只能产生一个对象,我们首先必须将类的构造器的访问权限设置为private,这样,就不能用new操作符在类的外部产生类的对象了,但在类内部仍可以产生该类的对象。因为在类的外部开始还无法得到类的对象,只能调用该类的某个静态方法以返回类内部创建的对象,静态方法只能访问类中的静态成员变量,所以,指向类内部产生的该类对象的变量也必须定义成静态的

单例模式的核心四步
1.私有化构造器
2.内部提供一个当前类的实例
3.提供公共的静态的方法,返回当前类的对象
4.返回的实例也必须静态化
饿汉式
class Singleton {
    // 1.私有化构造器
    private Singleton() {
    }

    // 2.内部提供一个当前类的实例
	// 4.此实例也必须静态化
    private static Singleton single = new Singleton();

    // 3.提供公共的静态的方法,返回当前类的对象
    public static Singleton getInstance() {
        return single;
    }
}
懒汉式(会有线程安全的问题)
class Singleton {
    // 1.私有化构造器
    private Singleton() {
    }

    // 2.内部提供一个当前类的实例
    // 4.此实例也必须静态化
    private static Singleton single;

    // 3.提供公共的静态的方法,返回当前类的对象
    public static Singleton getInstance() {
        if (single == null) {
            single = new Singleton();
        }
        return single;
    }
}
区分 饿汉式 和 懒汉式

  饿汉式:	
  	坏处:对象加载时间过长。
  	好处:饿汉式是线程安全的
  
  懒汉式:好处:延迟对象的创建。
		  目前的写法坏处:线程不安全。--->到多线程内容时,再修改
单例(Singleton)设计模式-应用场景

重量级应用都用单例模式,减少创建和销毁的压力。

	网站的计数器,一般也是单例模式实现,否则难以同步。
	应用程序的日志应用,一般都使用单例模式实现,这一般是由于共享的日志文件一直处于打开状态,因为只能有一个实例去操作,否则内容不好追加。
	数据库连接池的设计一般也是采用单例模式,因为数据库连接是一种数据库
资源。 
	项目中,读取配置文件的类,一般也只有一个对象。没有必要每次使用配置文件数据,都生成一个对象去读取。 
    Application 也是单例的典型应用
    Windows的Task Manager (任务管理器)就是很典型的单例模式
    Windows的Recycle Bin (回收站)也是典型的单例应用。在整个系统运行过程中,回收站一直维护着仅有的一个实例。

关键字final

final 赋值注意点

首先final的变量只能赋值一次,所以赋值的位置只能是 显式初始化代码块中初始化构造器中初始化 三种:

① 显示初始化,最常用;

② 代码块赋值,赋值操作比较复杂时使用,例如通过调用方法去赋值;

③ 构造器赋值,要注意,如果用构造器去赋值的话,那么每个构造器都要对那个属性进行初始化赋值,否则就会报错,因为其他构造器没有进行赋值的话相当于没有赋值,所以会编译报错;

④ 就算是在实体类里面对 final 属性进行赋值,也要遵循只赋值一次的规则。

/*
 * final:最终的
 * 
 * 1. final可以用来修饰的结构:类、方法、变量
 * 
 * 2. final 用来修饰一个类:此类不能被其他类所继承。
 *          比如:String类、System类、StringBuffer类
 * 
 * 3. final 用来修饰方法:表明此方法不可以被重写
 * 			比如:Object类中getClass();
 * 
 * 4. final 用来修饰变量:此时的"变量"就称为是一个常量
 * 	    4.1 final修饰属性:可以考虑赋值的位置有:显式初始化、代码块中初始化、构造器中初始化
 * 		4.2 final修饰局部变量:
 *           尤其是使用final修饰形参时,表明此形参是一个常量。当我们调用此方法时,给常量形参赋一个实参。一旦赋值
 *           以后,就只能在方法体内使用此形参,但不能进行重新赋值。
 *           
 *  static final 用来修饰属性:全局常量
 */
public class FinalTest {
	
	final int WIDTH = 0;
	final int LEFT;
	final int RIGHT;
//	final int DOWN;
	
	{
		LEFT = 1;
	}
	
	public FinalTest(){
		RIGHT = 2;
	}
	
	public FinalTest(int n){
		RIGHT = n;
	}
	
//	public void setDown(int down){
//		this.DOWN = down;
//	}
	
	
	public void doWidth(){
//		width = 20;
	}
	
	
	public void show(){
		final int NUM = 10;//常量
//		NUM += 20;
	}
	
	public void show(final int num){
//		num = 20;//编译不通过
		System.out.println(num);
	}
	
	
	public static void main(String[] args) {
		
		int num = 10;
		
		num = num + 5;
		
		FinalTest test = new FinalTest();
//		test.setDown(3);
		
		test.show(10);
	}
}


final class FinalA{
	
}

//class B extends FinalA{
//	
//}

//class C extends String{
//	
//}

class AA{
	public final void show(){
		
	}
}

class BB extends AA{
	
//	public void show(){
//		
//	}
}

final 面试题

第一题:

解析:

考察了对 final 修饰属性,属性值不变的知识。

++x 编译报错,因为 ++x 除了返回 x+1 之外还改变了 x 的值。

x + 1 编译通过,因为 x+1 不改变 x 的值。

第二题:

解析:

o = new Other (); ,编译报错,因为 final 的形参,已经不可变了。

o.i++ ,编译通过,因为 o 才是 final 的,而里面的属性不是 final 的。