温故而知新 (三) 之 关键字final、static以及方法参数

1.final关键字

在Java中,final关键字可以用来修饰类、方法和变量(包括成员变量和局部变量)

  • 当用final修饰一个类时,表明这个类不能被继承。也就是说,如果一个类你永远不会让他被继承,就可以用final进行修饰。final类中的成员变量可以根据需要设为final,但是要注意final类中的所有成员方法都会被隐式地指定为final方法。
  • final修饰的方法表示此方法已经是“最后的、最终的”含义,亦即此方法不能被重写(可以重载多个final修饰的方法)。此处需要注意的一点是:因为重写的前提是子类可以从父类中继承此方法,如果父类中final修饰的方法同时访问控制权限为private,将会导致子类中不能直接继承到此方法,因此,此时可以在子类中定义相同的方法名和参数,此时不再产生重写与final的矛盾,而是在子类中重新定义了新的方法。(注:类的private方法会隐式地被指定为final方法。)
  • 当final修饰一个基本数据类型时,表示该基本数据类型的值一旦在初始化后便不能发生变化;如果final修饰一个引用类型时,则在对其初始化之后便不能再让其指向其他对象了,但该引用所指向的对象的内容是可以发生变化的。本质上是一回事,因为引用的值是一个地址,final要求值,即地址的值不发生变化。
package pri.gitonline.keyword;

/**
 * 关键字 final
 * 
 * @author gitonline
 *
 */
public class Keyword_Final {

	// 1.修饰类
	final class A {

	}
	
	// 当用final修饰一个类时,表明这个类不能被继承。
	// 也就是说,如果一个类你永远不会让他被继承,就可以用final进行修饰。
	// final类中的成员变量可以根据需要设为final,但是要注意final类中的所有成员方法都会被隐式地指定为final方法。
//	class B extends A {
//
//	}
	
//----------------------------------------------------------------
	
	//2.修饰方法
	class M{
		/**
	     * 	因为private修饰,子类中不能继承到此方法,因此,子类中的getName方法是重新定义的、
	     * 	属于子类本身的方法,编译正常
	     */
		private final void getName() {
			//类的private方法会隐式地被指定为final方法
		}
		/**
		 * 	 因为public修饰,子类可以继承到此方法,导致重写了父类的final方法,编译出错
		 */
//		public final void getName() {
//			
//		}
	}
	
	class N extends M{
		public void getName() {
			System.out.println("重新定义");
		}
	}

//----------------------------------------------------------------

	
	//3.修饰变量
	/**
	 * 	当final修饰一个基本数据类型时,表示该基本数据类型的值一旦在初始化后便不能发生变化;
	 * 	如果final修饰一个引用类型时,则在对其初始化之后便不能再让其指向其他对象了,
	 * 	但该引用所指向的对象的内容是可以发生变化的。本质上是一回事,因为引用的值是一个地址,
	 * 	final要求值,即地址的值不发生变化。
	 * @author gitonline
	 *
	 */
	class X {
		private final int i=0;
		private final int a;
		private final StringBuffer s = new StringBuffer("test");
		
		public X() {
			a=1;
		}
		
		public void handle() {
//			i++;
//			s = new StringBuffer("good");
		}
	}
	
	//4.深入使用
	/**
	 * 	可参考
	 * <a>https://www.cnblogs.com/xiaoxi/p/6392154.html</a>
	 */
}

2.static

static可以用来修饰类的成员方法、类的成员变量,另外可以编写static代码块来优化程序性能。

被static关键字修饰的方法或者变量不需要依赖于对象来进行访问,只要类被加载了,就可以通过类名去进行访问。

package pri.gitonline.keyword;

/**
 * 	关键字 static
 * @author duke
 *
 */
public class Keyword_Static {
	
	//1.static修饰方法
	//static方法一般称作静态方法,由于静态方法不依赖于任何对象就可以进行访问,
	//因此对于静态方法来说,是没有this的,因为它不依附于任何对象,既然都没有对象,就谈不上this了。
	//并且由于这个特性,在静态方法中不能访问类的非静态成员变量和非静态成员方法,
	//因为非静态成员方法/变量都是必须依赖具体的对象才能够被调用。
	private static String A = "HELLO";
	private String B = "NO";
	
	public Keyword_Static() {
		
	}
	
	public void handleMethodA() {
		System.out.println(A);
		System.out.println(B);
		handleMethodB();
	}
	
	/**
	 * 	独立于对象存在的,可以直接用过类名调用
	 */
	public static void handleMethodB() {
		System.out.println(A);
//		System.out.println(B);//编译错误
//		handleMethodA();//编译错误
	}
	
	//2.static修饰变量(static是不允许用来修饰局部变量)
	//static变量也称作静态变量,静态变量和非静态变量的区别是:
	//静态变量被所有的对象所共享,在内存中只有一个副本,它当且仅当在类初次加载时会被初始化。
	//而非静态变量是对象所拥有的,在创建对象的时候被初始化,存在多个副本,各个对象拥有的副本互不影响。

	//static成员变量的初始化顺序按照定义的顺序进行初始化。
	
	//3.static代码块
	//static关键字还有一个比较关键的作用就是 用来形成静态代码块以优化程序性能。
	//static块可以置于类中的任何地方,类中可以有多个static块。
	//在类初次被加载的时候,会按照static块的顺序来执行每个static块,并且只会执行一次。
	static {
		System.out.println("OK_A");
	}
	
	static {
		System.out.println("OK_B");
	}
	
	public static void main(String[] args) {
		//验证 static代码块
		Keyword_Static a = new Keyword_Static();
		Keyword_Static b = new Keyword_Static();
	}
	
	//4.关于构造器是否是static方法
	//构造器内可以使用this指代当前对象,但是static不依附任何对象,所以构造器肯定不是static方法
	
	//5.深入理解static的应用
	/**
	 * 	<a>https://www.cnblogs.com/dolphin0520/p/3799052.html</a>
	 */
}

 

3.方法参数

Java程序设计语言总是采用按值调用,也就是说,方法得到的是所有参数值的一个拷贝

基本数据类型拷贝的是数值本身,而引用数据类型是拷贝对象的引用。

public class Data {

	public static void main(String[] args) {
		int a =0;
		StringBuffer b = new StringBuffer("a");
		Data d = new Data();
		System.out.println(a+","+b);
		d.add(a,b);
		System.out.println(a+","+b);
	}
	
	public void add(int a,StringBuffer b) {
		a = a+10;
		b.append("OK");
	}
}

结果: 

0,a
0,aOK

验证Java是按值传递而非引用传递的例子

package pri.gitonline.test;

/**
 * 提供一个引用类型
 * @author gitonline
 * 2019年4月30日
 */
public class User {
	
	private Integer id;
	private String name;
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public User(Integer id, String name) {
		super();
		this.id = id;
		this.name = name;
	}
	public User() {
		super();
	}

}

验证demo:

package pri.gitonline.test;

public class Swap {
	
	public static void swap(User u1,User u2) {
		User temp = u1;
		u1 = u2;
		u2 = temp;
		System.out.println(u1.getId()+","+u2.getId());
	}
	
	public static void main(String[] args) {
		User user1 = new User(1, "小明");
		User user2 = new User(2, "小李");
		System.out.println("传递开始:"+user1+","+user2);
		swap(user1, user2);
		System.out.println("传递结束:"+user1+","+user2);
	}
}

结果:

传递开始:pri.gitonline.test.User@2a139a55,pri.gitonline.test.User@15db9742
2,1
传递结束:pri.gitonline.test.User@2a139a55,pri.gitonline.test.User@15db9742

描述:

       假若按引用传递,传递的参数应该是参数u1、u2的引用(地址)。swap函数接收的应该是原始值的内存地址,而传递结束的结果应该u1、u2换了位置的。

        可是结果很明显传递的参数仅仅只是对象u1,u2的参数值(引用字面值),执行swap方法后并未发生变化。swap方法内对u1、u2的操作,仅仅可以改变传过来对应对象属性,无法对实际参数的地址进行改变,形参改变无法导致实参改变,形参只是实参地址一个拷贝(拷贝的是引用地址字面值)。即按值传递。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值