本文主要讲述java基础中的this关键字和final关键字的定义以及其用法,还通过例题详细介绍了java的值传递机制。
一、this关键字
1、什么是this关键字
this关键字代表当前对象
2、为什么使用this关键字
有时不方便直接使用对象,需要用this关键字来代替
3、如何用this关键字
(1)this.属性
this.属性一般表示在类当中调用全局变量
程序代码 :
public class Student {
public String name;
public void run(String aaaa){
this.name=aaaa;
}
}
public class Test {
public static void main(String[] args) {
Student student= new Student();
ce.run("aaaa");
Student student1= new Student();
ce.run("hhhh");
}
}
代码分析:
①程序堆栈运行图如下
②为什么设置对象名称student和student1
原因:需要区分你调用的是哪个run方法,所以添加一个对象名称
③this.name调用的是全局变量为什么不是局部变量。
原因:因为全局变量属于当前对象,而局部变量不属于全局变量。
(2)this.方法名
①代码:调用没有static关键字的方法
例:
public class Student {
public String name;
public void run(String name){
this.name=name;
}
public void aaa(){
this.run("aaaa")
}
}
②代码:调用有static关键字的方法
注意:
此代码中run方法被static修饰,他就不能在调用this代码,应该去掉,报错图在代码下
原因:
①static修饰的代码被所有对象共享,所以this可以调用static修饰的方法
②static修饰的方法当中不能出现this关键字,因为类是构建对象的模板,有类不一定有对象
例:
public class Student {
public String name;
public static void run(String name){
/*this.name=name;该语句删掉,static修饰的方法当中不能出现this关键字*/
}
public void aaa(){
this.run("aaaa")
}
}
(3)this() //了解就行,this的用法主要体现在 this.属性和this.方法名。
this()表示访问构造器,指的是构造器的调用,
注意:
①this()不能再普通方法中使用,只能在构造方法中使用
示例代码如下:
public class Student {
public String name;
public Student(){
}
public Student(String name){
this() ;
}
}
②this()在构造方法中使用的必须是第一条语句
③在一个类下两个构造方法中不能通过this()相互调用
示例代码如下:
public class Student {
public String name;
public Student(){
this("nnnn")/*此时该处会发生报错*/
}
public Student(String name){
this() ;
}
}
④不能与super()同时使用
二、final关键字
final关键可以修饰变量、方法和类。
1、final修饰类
final所修饰的类不能被继承
示例代码如下:
public final class A{
}
public class B extends A{
/* 注意此时会报错,final修饰的类不能被继承*/
}
2、final修饰方法
final修饰的方法不能被重写
示例代码如下:
public class Student {
public String name;
public void final run(){
System.out.pritnln("aaa");
}
}
public class Test extends Student {
/* 此处会报错,final修饰的方法不能被重写*/
public void run(){
System.out.pritnln("bbb");
}
}
3、final修饰变量
final所修饰的变量叫做常量,常量是只能被赋值一次的变量,常量的变量名必须大写。
(1)final修饰全局变量和局部变量
①final修饰全局变量
全局变量:在类里边所定义的变量
fianl修饰全局变量需要赋值,否则会报错。
示例代码如下:
未赋初始值:
赋初始值:
原因:final所修饰的变量叫做常量,常量只能被赋值一次,而全局变量具有默认值(根据数据类型),所以需要赋初始值。
补充:数据默认值
引用数据类型:默认值为null
整形:默认值为0
浮点型:默认值为0.0
布尔型:默认值为flase
char类型:默认值为空
②final修饰局部变量
局部变量:在方法里边定义的变量
fianl修饰局部变量不需要赋值,但如果要使用则必须赋值,否则会报错。但局部变量如果不被final修饰,在使用时也需要赋初始值。所以加不加final对局部变量影响不大
示例代码如下:
(2)final修饰基本数据类型所定义的变量和引用数据类型所定义的变量
①final修饰基本数据类型所定义的变量
fianl修饰的基本数据类型,其值不能被改变
原因:对于基本数据类型而言,final固定的是其对象的值,不能被改变(对于基本数据类型来说对象存储的是他本身的值例如int a=10,存储的是10,而被final修饰后10就不能被改变了,所以在修改时会发生报错),详细流程图如下可对照引用数据类型观看
示例代码如下:
例:基本数据类型 没有被final修饰
public class Student {
public String name;
int a=10;
public void run(){
a=11;
}
}
例:基本数据类型 被final修饰
public class Student {
public String name;
final int A=10;
public void run(){
A=11;/*此时这里会发生报错*/
}
}
流程图:
②final修饰引用数据类型所定义的变量
引用数据类型:
引用数据类型包括:类、数组、接口
对于引用数据类型而言,final固定的是对象的地址,变量无法改变其指向对象的地址,而对象当中的内容是可以改变的(参考两个引用类型的赋值操作和给一个引用类型的某个值进行修改)具体流程图如下。
示例代码如下:
例:没有用final修饰引用类型数据
public class Student {
int[]arr1 = new int[]{1,2,3};
int[]brr = new int[]{4,5,6};
public void change(){
arr1=brr;
}
public void change1(){
arr1[2]=10;
}
}
例:被final修饰的引用类型数据
public class Student {
int[]ARR1 = new int[]{1,2,3};
int[]BRR = new int[]{4,5,6};
public void change(){
ARR1=BRR;/*此时,该处代码会发生报错*/
}
public void change1(){
ARR1[2]=10;
}
}
流程图:
三、java的值传递
通过示例代码来了解java的值传递
1、示例1:
(1)示例代码如下:
public class A {
public static void main(String[] args) {
String nameString ="张三";
name(nameString);
System.out.println("main--- > "+nameString);
}
public static void name (String name) {
name ="李四";
System.out.println( "name---> "+name);
}
}
(2)输出结果如下:
name--->李四
name--->张三
(3)流程如下
画堆栈流程图,第一步main方法入栈,然后定义一个nameString字符串其值为"张三"的存储地址0x1,"张三"存储在方法区的字符串常量池中,其地址为0x1。
第二步调用name(nameString)方法入栈,该方法中有一个String类型的局部变量name,其值为nameString字符串的值即0x1(主要java只有值传递),然后方法继续进行 name="李四",此时在字符串常量池中先存储"李四"其地址为0x2,再把0x2赋值给name(记住java是值传递,只传送变量的值,不传送变量其本身,所以nameString并不会发生改变)。最后输出,输出的是name--->李四。
第三步输出完之后name(nameString)方法出栈,回到main方法中,在执行输出,输出的是name--->张三。
2、示例2:
(1)示例代码如下
public class Person {
private String nameString;
private int age;
public Person (String nameString,int age){
this.age=age;
this.nameString=nameString;
}
@Override
public String toString(){
return "Person [nameString="+ nameString +",age="+age+"]";
}
public static void name(Person person){
person.age=20;
person.nameString="李四";
person=null;
}
public static void main(String[] args) {
Person person =new person("张三",18);
System.out.println(person.toString());
name(person);
System.out.println(person.toString());
}
}
(2)输出结果如下
张三 18
李四 20
(3)流程如下
画出堆栈流程图,第一步main方法入栈,创建person对象地址为0x1,该对象包含(nameString=0x2,age=18,toString(),name(),)方法区存储张三的地址值为0x2,调用toString方法,输出张三 18。
第二步,name方法入栈,name方法中有一个局部变量person,同时对他进行了值传递,person的值为0x1,同时namestring的值被改为李四的地址值0x3,age改为20,改完之后person置空,出栈,然后进行toSting方法的调用,注意此时0x1中的内容已经被修改,输出李四 20。
3、示例3:
(1)示例代码如下
public class Student {
private String name;
private int age;
public Student(String name,int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + "]";
}
public static void change(Student s1, Student s2){
Student temp = new Student( name: "王五", age: 20);
temp = s1;
s1 = s2;
s2 = temp;
}
public static void main(String[] args) {
Student zhangsan = new Student( name: "张三", age: 18);
Student lisi = new Student( name: "李四", age: 20);
Student.change(zhangsan, lisi);
System.out.println(zhangsan.toString());
System.out.println(lisi.toString());
}
}
(2)输出结果如下
张三 18
李四 20
(3)流程如下(流程图为了方便画图,直接把字符串写在对象内了,应该在字符串常量池,change()方法也没写。)
画出堆栈流程图,main方法入栈,创建zhansa值为0x1(name =0x3 、age=18、),和lisi对象值为0x2(name =0x4 、age=20、),张三0x3和李四0x4都存储在字符串常量池中。
调用change方法,注意change方法被static修饰存储在方法区中,创建一个Student类型的 对象temp值为0x5(name =0x6 、age=20、)王五0x6存储在字符串常量池中和对象s1值为0x1和对象s2值为0x2。接着将s1即0x1传给temp,再将s2的值即0x2传给s1,最后将temp值即0x1传给s2。
然后出栈,注意上述修改并没有对zhangsan和对象lisi所指向的地址造成影响,输出为张三 18 李四 20。
4、示例4:
(1)示例代码如下
class Two{
byte x;
}
public class Student {
public static void main(String[] args){
Student student = new Student();
student.start(;
}
void start( {
Two two = new Two();
System.out.print(two.x +" ");Two two2 = fix(two);
System.out.println(two.x + " "+two2.x);
}
Two fix(Two tt) {
tt.x =42;return tt;
}
}
(2)输出结果如下
0
42 42
(3)流程如下
画堆栈内存图,main方法入栈,创建 student对象0x1(start()、fix()),调用start()方法,创建一个two对象0x2(byte x),此时没有赋值,默认值为0。然后进行输出0。
然后生成一个two2对象,他指向的值由fix方法决定,fix()方法入栈将0x2的地址赋值给tt,然后将0x2中x的值改为42,返回tt即0x2,所以two2的值为0x2,此时输出42 42。