这篇文章记录了学 java 以来的的全部笔记并不断进行更新,希望能坚持住吧~
这篇文章记录了学 java 以来的的全部笔记并不断进行更新,希望能坚持住吧~
方法的重载和重写 Overload 和 Override#
方法的重载 Overload:一个类中,多个方法的方法名相同,但是参数列表不同(可以是个数不同,类型不同,顺序不同)。让类以统一的方式处理不同的数据类型的实现方法,调用方法时传递不同个数或者类型的参数来决定调用哪一个方法。注意,方法名字相同,参数列表不同,返回类型等其他的可以相同也可以不同,Java 虚拟机通过参数列表进行判断。所以需要一个独一无二的参数列表。
方法的重写 Override:在子类中重写父类存在的方法,对父类的方法进行扩展,新增加功能,重写是建立在继承的关系之上的。重写的方法的方法签名需要与父类对应的方法签名完全一致(方法签名指的是方法名称和参数列表)。Override 体现了 java 的多态性。
多态是同一个行为具有多个不同表现形式或形态的能力。
多态性是对象多种表现形式的体现。
现实中,比如我们按下 F1 键这个动作:
如果当前在 Flash 界面下弹出的就是 AS 3 的帮助文档;
如果当前在 Word 下弹出的就是 Word 帮助;
在 Windows 下弹出的就是 Windows 帮助和支持。同一个事件发生在不同的对象上会产生不同的结果。多态存在的三个必要条件:1. 继承 2. 重写 3. 父类引用指向子类对象。针对某个类型的方法调用,其真正执行的方法取决于运行时期实际类型的方法。
重写时可以修改访问权限修饰符,要求:子类重写方法的权限修饰符应大于或者等于父类方法的权限修饰符,比如父类的是 protect,你重写完可以改为 public,或者父类是 default 权限,你也可以改为 public 权限或者 protect 权限,访问权限只能大,不能小。
重写时可以修改为不同的返回值类型,要求:仅当返回值为引用数据类型时 (返回值类型是引用数据类型,而不能是 int 等基本数据类型),这样才可以修改返回值类型,且必须是 - 父类方法返回值类型的子类;要么就不修改,与父类返回值类型相同,比如父类的返回值类型是 Object,这时候,你子类的返回值类型可以为 Object,也可以任意一个类。只能小,不能大。
访问修饰符#
访问修饰符 | 本类 | 同包 | 子类 | 其他 |
---|---|---|---|---|
private | √ | × | × | × |
default | √ | √ | × | × |
protected | √ | √ | √ | × |
public | √ | √ | √ | √ |
参数绑定#
调用方把参数传递给实例方法时,调用时传递的值会按参数位置一一绑定。
public class Main {
public static void main(String[] args) {
Person p = new Person();
int n = 15; // n的值为15
p.setAge(n); // 传入n的值
System.out.println(p.getAge()); // 15
n = 20; // n的值改为20
System.out.println(p.getAge()); // 15还是20?
}
}
class Person {
private int age;
public int getAge() {
return this.age;
}
public void setAge(int age) {
this.age = age;
}
}
运行代码,从结果可知,修改外部的局部变量 n,不影响实例 p 的 age 字段,原因是 setAge () 方法获得的参数,复制了 n 的值,因此,p.age 和局部变量 n 互不影响。
结论:基本类型参数的传递,是调用方值的复制。双方各自的后续修改,互不影响。
我们再看一个传递引用参数的例子:
public class Main {
public static void main(String[] args) {
Person p = new Person();
String[] fullname = new String[] { "Homer", "Simpson" };
p.setName(fullname); // 传入数组fullname
System.out.println(p.getName()); // "Homer Simpson"
fullname[0] = "Bart"; // fullname数组的第一个元素修改为"Bart"
System.out.println(p.getName()); // "Homer Simpson"还是"Bart Simpson"?
}
}
class Person {
private String[] name;
public String getName() {
return this.name[0] + " " + this.name[1];
}
public void setName(String[] name) {
this.name = name;
}
}
注意到 setName () 的参数现在是一个数组。一开始,把 fullname 数组传进去,然后,修改 fullname 数组的内容,结果发现,实例 p 的字段 p.name 也被修改了!
结论:引用类型参数的传递,调用方的变量,和接收方的参数变量,指向的是同一个对象。双方任意一方对这个对象的修改,都会影响对方(因为指向同一个对象嘛)。
下面这个例子:
public class Main {
public static void main(String[] args) {
Person p = new Person();
String bob = "Bob";
p.setName(bob); // 传入bob变量
System.out.println(p.getName()); // "Bob"
bob = "Alice"; // bob改名为Alice
System.out.println(p.getName()); // "Bob"还是"Alice"?
}
}
class Person {
private String name;
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
}
结论没问题:
1、整数、浮点数、字符是基本类型。
2、字符串、数组是引用类型(内存数据的索引)
3、基本类型参数的传递,是调用方值的复制。双方各自的后续修改,互不影响。
4、引用类型参数的传递,调用方的变量和接收方的参数变量,指向的是同一个对象。双方任意一方对这个对象的修改,都会影响对方。
那么 3 个例子中,
1、整数的参数传递理解了,复制出来的,分家了,自己管理自己的,类读出数据不变。
2、字符串数组的参数传递也理解了,都是指向同一个地方,数组的一个元素改了,类读出数据也就变了(类一直指向这里)。
3、字符串也是引用参数,为什么类读出数据不变?因为重写了整个字符串(新开内存和指向,参看字符串更改章节),类依然指向之前内存块,类读出数据不变,同结论 1。如果只是修改字符串内存中某一个字符的值,则同结论 2。
简单总结:类对基本类型是复制数据本身,新开内存。对引用类型是复制指向地址,内存数据本身变化了,类读出数据跟着变化。但字符串修改,是新开内存新指向,已经不能影响类数据。
(以上例子和总结来自于廖雪峰老师博客以及评论
构造方法#
Person p = new Person("Xiao Ming", 15);
new 后面的 person 指的是构造方法,调用构造方法必须使用 new 操作符。
在 Java 中,创建对象实例的时候,按照如下顺序进行初始化:
-
先初始化字段,例如,int age =10; 表示字段初始化为 10,double salary; 表示字段默认初始化为 0,String name; 表示引用类型字段默认初始化为 null;
-
执行构造方法的代码进行初始化。
构造方法的代码由于后运行。
构造方法也有多态性,可以自动根据参数列表匹配;
构造方法可以调用构造方法,使用 this. 关键字
native 关键字#
刚在看一问题:两个对象的 hashCode () 相同,则 equals () 也一定为 true 么? 查一下 hashCode () 的定义,
public native int hashCode();
第一次看到 native 关键字,好奇是什么东东。查了一番资料。
JNI#
首先要了解的是 JNI 即 Java Native Interface Java 本地方法接口,通过这个允许 Java 语言和 C 或 C++ 进行交互。维基百科是这样解释的:“当应用无法完全用 Java 编程语言实现的时候,(例如,标准 Java 类库不支持的特定平台特性或者程序库时),JNI 使得编程者能够编写 native 方法来处理这种情况”。这就意味着,在一个 Java 应用程序中,我们可以使用我们需要的 C++ 类库,并且直接与 Java 代码交互,而且在可以被调用的 C++ 程序内,反过来调用 Java 方法(回调函数)。 (这也太牛逼了吧…
总结来说就是:使用 native 关键字修饰的函数 (方法),说明这个方法是原生函数,也就是这个方法是用 C/C++ 语言实现的,并且被编译成了 DLL,由 java 去调用。 完活儿~
补充一个实现步骤 :
可以将 native 方法比作 Java 程序同C程序的接口,其实现步骤:
-
在 Java 中声明 native () 方法,然后编译;
-
用 javah 产生一个. h 文件;
-
写一个. cpp 文件实现 native 导出方法,其中需要包含第二步产生的. h 文件(注意其中又包含了 JDK 带的 jni.h 文件);
-
将第三步的. cpp 文件编译成动态链接库文件;
-
在 Java 中用 System.loadLibrary () 方法加载第四步产生的动态链接库文件,这个 native () 方法就可以在 Java 中被访问了。
后续学习网址:IBM 社区在 Windows 中实现 Java 本地方法为什么说多态可以消除类型之间的耦合关系?#
给你说了也白搭,你大概知道就行了,这个需要代码量。。。简单地说就是,没有多态,那么等号左边是啥度右边就得是啥,这就叫耦合,有了多态,知左边是父类(或者接口),右边是子类(或实现类),我只管调用接道口里面的方法就是了,至于你实现类怎么去实现,那是你的事,你要修改一下专实现,你只管去把实现类换属掉,我这边一行代码都不用变,这就解耦了