[疯狂Java]面向对象:命名规范、重载、值传递、可变参数、static/this

时间:2022-02-10 21:25:58

1. 命名规范:

    1) 类:由多个单词连缀而成,单词之间不要分隔符,每个单词首字母大写,其余小写;

    2) 数据成员:应该是名词,多个单词连缀而成,首字母小写,其余单词首字母大写,其余小写,中间不要使用分隔符;

    3) 方法:应该以英文动词开头,命名规则和数据成员相同;


2. 方法重载:

    1) 重载在所有语言中的最基本要求是一致的,必须、至少要求方法名要相同才会有重载的可能;

    2) 重载的条件——方法签名:

         i. 不同语言的方法签名不太相同,像Swift把返回值类型也加入到了方法签名中了,而有些语言像Java就不是;

         ii. Java规定的方法签名:就只有参数列表(参数个数、类型,但是不管形参名,形参名忽略),只有参数列表不同才会形成重载(不包括返回类型和方法修饰)!

    3) 为什么不加入返回值类型呢?Java是这样解释的,如果参数列表相同但返回值类型不同的方法,Java是允许调用方法不利用返回值的(即单独调用方法,例如对于int f();可以int a = f(); 也可以f();这样调用),即如果出现f()这样的调用方式编译器就无法判断应该使用哪个重载版本,即发生歧义,因此会编译报错!所以Java不把返回值类型加入方法签名中;


3. 方法的参数传递机制:值传递

    1) Java的方法参数传递全部采用值传递;

    2) 基本类型直接创建器副本作为参数,对于引用类型(对象,只能用引用来访问它)也是值传递,参数仅仅就是指针的副本;

    3) 因此swap方法只对基本类型有效,但是对引用类型无效,因为在内部交换的仅仅是两个副本引用,并不影响外部真正的实参;


4. 可变参数方法:

    1) 即printf那种参数个数不确定(可变)的方法;

    2) 定义语法:

         i. 可变参数的类型必须写成type...;

         ii. 例如:public void func(int a, String... args);

!! 传参的时候可变参数可以接受0个或多个实参!!

    3) 规则:和其它语言中的可变参数的规定还是基本一致的

         i. 可变参数必须是最后一个参数;

         ii. 可变参数最多只能有一个;

!!违反这两个规定都会导致调用时产生歧义,很容想明白;

    4) 可变参数底层使用数组实现的!!

         i. 上面的public void func(int a, String... args);可以这样调用:obj.func(5, new String[]{"abc", "def", "xyz"});

         ii. 因为可变参数实质上使用数组实现的,但是这里不能传入多个数组(只能传一个):obj.func(5, new String[]{"abc"}, new String[]{"xyz"});  // 错误!!!

    5) 尽量不要重载可变参数方法!!

         i. 原因是这样的,例子:test(int arg);  和  test(int... args);

         ii. 歧义发生在这样调用:test(5),这样会调用test(int arg),但由于两种方法执行内容可能相差很大,因此如果你想在只有一个参数时强制使用test(int... args)版本时就必须使用数组调用,test(new int[]{5});,但这样很麻烦;

         iii. 因此为了避免上述这种歧义的情况就尽量不要重载可变参数方法!!


2. static和this:

    1) 用static修饰的数据成员和方法都属于类,即静态成员,而没有static修饰的成员都属于对象;

    2) this:

         i. 是一个关键字,和C++的this指针一样,Java的this是引用;

         ii. 用来表示当前的对象本身的引用;

         iii. 在对象内部(方法、块)中可以通过this来引用自己,因此可以在方法中返回this等,例如:public MyType func() { return this; }

         iv. 通过this可以轻松地引用(在块或者方法中引用其他成员)对象自己的成员(数据、方法);

    3) this的另一个常见的用途:当方法形参和数据成员重名时可以用this明确指定身份,例如构造器中常见,Person(String name, int age) { this.name = name; this.age = age; }

    4) 对象方法和类方法的本质区别:

         i. 对象方法有一个隐藏参数this(是方法的第一个参数,但不过是隐藏的,用户看不见,底层作为方法的第一个参数传入),因此对象方法可以通过this来识别现在调用的是哪个对象的方法(对象只保存数据成员,所有对象都共享一份方法代码,而方法就是通过this指针来识别调用者的);

         ii. 而static修饰的类方法就没有this参数,因此静态方法不能访问非静态成员,但是对象方法就能访问静态成员;

    5) 省略this访问其他对象成员:

         i. Java语言本身规定,访问任何对象数据或者方法都必须加上对象前缀,即“obj.data、obj.func(...)"的形式;

         ii. 因此理论上在一个方法中调用另一个对象方法或者访问一个对象数据成员时应该都加上this前缀,即"this.func()"的形式;

         iii. 但这样大量地使用this会显得代码很臃肿,因此Java允许在对象本身的范围内引用对象的其它成员可以不加this前缀;

         iv. 所有没有对象前缀的成员引用编译器都会默认成使用this作为前缀!!因此可以省略this前缀;

    6) 为什么Java允许通过对象引用来访问类成员?!

         i. 讲道理的话在任何地方(不管是类内(外),还是对象内(外))访问类成员(静态成员,数据或方法)都应该使用类名作为前缀,即"MyType.data、MyType.func()"的形式;

         ii. 但Java也允许用对象应用来访问静态成员,即"obj.static_data、obj.static_func()",这显然非常不合理,容易造成误解!把静态成员错认为是对象成员!

         iii. 其实这也是由苦衷的!因为Java允许在类(对象)内部访问其他对象成员(静态、非静态)都可以省略前缀,而这些省略都将默认为是通过this引用的!因此那些省略前缀的静态成员也默认使用this作为前缀的,而为了准确地识别它们是静态成员,也就允许通过this来引用静态成员了,而this刚好是对象引用!

!也就是说这种别扭的漏洞是因为this的省略而引起的!!

     7) 总结:也就是说,如果用对象引用来访问静态成员那其实背后也是用类名来代理的,这就会有一个小问题,那就是用空的引用来放问静态成员也是能正常访问的!!

MyType a = null;
a.static_member;
!因为其背后还是用类名来代理的;

!!像这样的代码就非常误导人,因此一定要养成用类名来访问静态成员的好习惯!!