java类和对象的基础特性-1
https://developer.aliyun.com/article/1515748
4、局部变量
和c语言相比,java中的类的结构与c语言中的结构体类似,在java语言中,一个在类中、在方法外定义的变量称为成员变量,在类中定义的方法,称为成员方法,而在成员方法(外加普通方法)中定义的变量为局部变量。
局部变量的有效范围是在当前代码块的,例如:有这样一段代码
public static void function(int[]arr){ int i = arr.length; for (int j = 0; j < i - 1; j++) { for (int k = 0; k < j-1; k++) { if( arr[j]> arr[k]){ int tem = arr[j]; arr[j] = arr[k]; arr[k] = tem; } } } }
其中的i就为局部变量,j和k也是局部变量,只不过他们两个的作用范围都被限制在了for循环语句中,他们的作用范围如图:
其中的int[ ] arr 其实也是一个局部变量,他的作用范围为整个方法的内部
注意:类中成员变量不不赋值的话都会有一个默认值,这在前面的已经提过,但是如果是局部变量在定义的时候没有赋值(初始化)的话就会编译报错。
5、this关键字
在学习了局部变量的时候,结合private我们可以提出这样的一个问题,如果类中方法的传入的参数和我们要去修改的被private修饰的成员名一样的话会如何赋值,例如:在这个狗类中
class Dog { private String name; int age; public void dis(String name){ name = name; } public void GetName(){ System.out.println(name); } } class specialDog extends Dog { public void func() { System.out.println("the sepcial dog"); } } public class Test{ public static void main(String[] args) { Dog dog1 = new Dog(); dog1.dis("修勾"); dog1.GetName(); } }
我们修改dog1为继承了Dog的specialDog的对象,这里利用接口函数去修改他的name然后获取这个(打印)name:结果如下
null
显然是这个地方除了问题,有两个name,一个是Dog类中成员变量name,一个是Dog类中方法的局部变量name,编译器就默认name为局部变量中的类。
如果遇到这种情况该如何区分是局部变量还是成员变量中的变量呢? 在java语言中规定使用this关键字来代表本类的对象的引用,我们将上述代码中的 name = name 改为:
this.name = name
编译器就会区分,原来前面这个name指的是这个类中的成员变量。
修改后的运行结果:
如果没有加this关键字,就相当于把局部变量的name赋值给自己,然后成员变量的name没有被初始化,给出的默认值为null,打印结果就为null。在后面还会讲到this的其他用法。
3、类的构造方法
从我们上面的例子可以看出来,我们定义一个对象,初始化赋值过程都是在创建完对象之后赋值,那有没有一种办法可以在创建对象结束之前就可以赋值呢?答案是肯定的。
在类中除了这种成员访问或成员方法接口等来修改之外,还存在一种特殊类型的方法,那就是构造方法。每当我们实例化一个对象的时候,就会自动调用构造方法,(如果没有自己手动写构造方法,就会自己调用一个内容为空的构造方法,即一个不带参数的构造方法)
构造方法有如下几个特点:
1、构造方法没有返回值
2、构造方法名称要与其类名相同
3、在定义构造方法的时候,构造方法没有返回值,如普通方法不同的是,构造方法不用在前面加上void返回类型的字样。
4、类中默认提供一个不带参数的构造方法
5、如果自己提供了一个构造方法,那么编译器默认不再提供不带参数的构造方法。
如果自己提供了一个不是不带参数的构造方法,那么当你企图用一个无参构造方法去实例化一个对象的时候就会报错,因为他在里面找不到不带参数的构造方法,此时编译报错。
其语法格式如下:
class A{ public A(){ ..... // 构造内容 } }
举例:
class Dog { private String name; int age; public Dog(String name,int age){ this.name = name; this.age = age; System.out.println("狗名为:"+this.name); System.out.println("狗龄为:"+this.age); } } public class Test{ public static void main(String[] args) { Dog dog1 = new Dog("修勾",5); } }
结果为:
事实上,this也可以调用类中的构造方法,看实例:
class Dog { private String name; int age; public Dog(String name){ this.name = name; System.out.println(this.name); } public Dog(){ this("this调用无参构造方法"); System.out.println("无参构造方法"); } } public class Test{ public static void main(String[] args) { Dog dog1 = new Dog(); } }
其调用顺序为:
除了构造方法以外,更方便的也可以直接进行对成员变量的幅值,这样就修改了成员变量的初始值。后面仍然可以对其进行赋值操作。
同时,构造方法也支持重载,在传入不同的参数需要对应做出不同的反应的时候,这个时候就可以将构造方法重载。
4、static:静态变量、常量、方法
1、static关键字
我们知道,不同的对象有不同的属性,这些属性包括动态属性和静态属性(这里的静态属性不是值得静态static修饰的属性,而是类的成员变量)。但是我们在处理问题的时候,可能会遇到不同对象要使用同一个数据的情况,就比如设计一个球类和圆类,他们在计算的时候都会需要用到一个PI(π)常量,如果用常规方法在这两个类中都定义一个PI成员,系统就会将这两个不在同一个类的成员分配到不同的内存中造成空间浪费。为了解决这个问题,可以使用static关键字,将这个常量设置为静态的。用图表示为:
由static修饰的成员属于类所有,同时这个成员不再依赖于对象,可以直接使用这样的语法形式来访问这个static修饰的成员:
类名.被static修饰的成员
也可以使用对象.static成员的方法来使用,但是不推荐,因为对象. 的形式访问是面向对象的常用访问方法,在这里容易错误的将static成员看成非static成员。
static修饰的成员仍然受权限修饰符的限制。
注意:
静态方法中无法使用this关键字
this是在实例化一个对象的时候使用,然后静态成员或者方法是在类形成的时候就创建的,因此静态方法不能直接使用非静态方法。
2、static修饰的代码块
在使用任何被static修饰的变量的时候,或者是在使用某些方法之前,需要初始化static变量,为了除了这种情况,java提供了static修饰的代码块,在加载类的时候就执行,初始化这些变量,以达到这种需求:
class Dog { public static String name; public static int age; static{ name = "xiaoli" age = 5 } }
static修饰的成员成为静态成员,被static修饰的语句或者语句块成为静态语句或者静态代码块。
在实例化一个对象的时候,所有静态代码块会首先依次执行完,在第二次创建对象的时候这个这些被static修饰的语句或者代码块不会再执行。
class Dog { public String name; public int age; static{ System.out.println("静态代码块执行"); } { System.out.println("实例代码块执行"); } public Dog(String name,int age){ System.out.println("构造代码块执行"); this.name = name; this.age = age; System.out.println("狗名为:"+this.name); System.out.println("狗龄为:"+this.age); } } public class Test{ public static void main(String[] args) { Dog dog1 = new Dog("修勾",5); Dog dog2= new Dog("大狗",8); } }
运行结果为:
可以看出来,静态代码块在构造方法之前执行,且只会执行一次,第二次创建对象的时候不会再执行。实例代码块在静态代码块之后,构造方法之前执行,但是实例代码块每次在创建对象的时候都会执行。
3、面试题
为了让读者更好的理解静态方法的使用,请看例题:
下面关于静态方法说明正确的是
A.在静态方法中可用this来调用本类的类方法
B.在静态方法中调用本类的静态方法时可直接调用
C.在静态方法中只能调用本类中的静态方法
D.在静态方法中绝对不能调用实例方法
解析:
静态方法中没有this关键词,因为静态方法是和类同时被加载的,而this是随着对象的创建存在的,静态比对象优先存在,因此选项A错误。也就是说,静态可以访问静态,但静态不能访问非静态而非静态可以访问静态。
在静态方法中可直接调用本类的静态方法,也可以通过类名.静态方法名的方式来调用其他类的静态方法,选项C错误。
D选项,静态方法不能直接调用实例方法和对象,但可以通过在静态方法中创建类的实例的方式间接调用
本次内容完........