参考链接:https://github.com/wind0926/JAVA2020
Java都是值传递
https://blog.csdn.net/bjweimengshu/article/details/79799485
Java 不能隐式执行向下转型,损失精度
显式转型:double x; float y = (float) x;
注意:float x = 1.1; //是错的,因为1.1是double型
,应该是float x = 1.1f;
获取变量的数据类型
public static void getType(Object x) {
System.out.println(x.getClass().toString());
}
switch(x){case "a": xxxx; break; case "b":...};
不支持long类型
package xuexi1;
public class Main{
public int x;
public static int y = 300;
public Main(int x) {
this.x = x;
System.out.println("Main‘s constructor");
}
public void fun() {
System.out.println("外部类输出: "+x);
}
//1.常规内部类
public class Main1{
int x1;
public Main1(int x1) {
this.x1 = x1;
System.out.println("Main1‘s constructor");
}
public void fun1() {
System.out.println("常规内部类输出 x: "+x); //可以调用外部类的变量
System.out.println("常规内部类输出 x1: "+x1); //输出自己内部类的变量
}
}
//2.静态内部类
/* 静态内部类与静态内部方法相似,只能访问外部类的static成员,不能使用this关键字*/
public static class Main2{
public void fun2() {
System.out.println("静态内部类输出 y: "+y); //可以调用外部类的静态变量
}
}
//3.局部内部类
/*在方法体或语句块(包括方法、构造方法、局部块或静态初始化块)内部定义的类成为局部内部类。
局部内部类不能加任何访问修饰符,因为它只对局部块有效。
1).局部内部类只在方法体中有效,就想定义的局部变量一样,在定义的方法体外不能创建局部内部类的对象
2).在方法内部定义类时,应注意以下问题:
①.方法定义局部内部类同方法定义局部变量一样,不能使用private、protected、public等访问修饰说明符修饰,也不能使用static修饰,但可以使用final和 abstract修饰
②.方法中的内部类可以访问外部类成员。对于方法的参数和局部变量,必须有final修饰才可以访问。
③.static方法中定义的内部类可以访问外部类定义的static成员*/
public Object fun_waibu() { //先构造一个外部类的方法,输出为Object
//再创建里面的一个局部内部类
class Main3{
int x3 = 500;
public String toString() { //因为方法输出的是Object,所以内部类的方法也只能是重写Object支持的方法
return "this is Main3‘s toString, waibu class‘s x = "+x;
}
}
return new Main3(); //在此new局部内部类,这样的话,在main函数中可以直接调用fun_waibu()来生成此内部类
}
//4.匿名内部类
/*1.匿名内部类可以继承一个类或实现一个接口,这里的ClassOrInterfaceName是匿名内部类所继承的类名或实现的接口名。但匿名内部类不能同时实现一个接口和继承一个类,也不能实现多个接口。如果实现了一个接口,该类是Object类的直接子类,匿名类继承一个类或实现一个接口,不需要extends和implements关键字。
2.由于匿名内部类没有名称,所以类体中不能定义构造方法,由于不知道类名也不能使用关键字来创建该类的实例。实际上匿名内部类的定义、构造、和第一次使用都发生在同样一个地方。此外,上式是一个表达式,返回的是一个对象的引用,所以可以直接使用或将其复制给一个对象变量。*/
//4.1 实现接口的匿名内部类
interface Jiekou{
public void jiekou_fun();
}
public void fun_waibu1() {
Jiekou main4 = new Jiekou() { //不需要implements关键词
public void jiekou_fun() { //实现接口的jiekou_fun()方法
System.out.println("this is niming class1");
}
};
main4.jiekou_fun(); //调用匿名类的方法
}
//4.2 继承类的匿名内部类,先不看
//4.3 继承Object
public Object fun_waibu2() {
return new Object(){
public String toString() {
return "this is niming class 2";
};
};
}
/* 内部类与外部类区别:内部类可以访问外部类所有的方法和属性,如果内部类和外部类有相同的成员方法和成员属性,
* 内部类的成员方法调用要优先于外部类即内部类的优先级比较高(只限于类内部,在主方法内,内部类对象不能访问外部类的成员方法和成员属性),
* 外部类只能访问内部类的静态常量或者通过创建内部类来访问内部类的成员属性和方法。
* */
public static void main(String[] args) {
Main A = new Main(100);
A.fun();
//构造常规内部类
Main.Main1 B = A.new Main1(200); //需要利用外部类(A)来构造
B.fun1();
//构造静态内部类
Main.Main2 C = new Main.Main2();
C.fun2();
//构造局部内部类
Object D = A.fun_waibu();//方法一:用已经new的对象A来构造
Object D1 = new Main(100).fun_waibu(); //方法二:现场new Main(100)
System.out.println("D1.type: "+D1.getClass().toString());
System.out.println("局部内部类输出: "+D.toString());
//构造匿名内部类
A.fun_waibu1();
System.out.println(A.fun_waibu2().toString());
}
}
result:
Main‘s constructor
外部类输出: 100
Main1‘s constructor
常规内部类输出 x: 100
常规内部类输出 x1: 200
静态内部类输出 y: 300
Main‘s constructor
D1.type: class xuexi1.Main$1Main3
局部内部类输出: this is Main3‘s toString, waibu class‘s x = 100
this is niming class1
this is niming class 2
5.Native关键词
https://blog.csdn.net/bifuguo/article/details/81513526
native 即 JNI,Java Native Interface
使用native关键字说明这个方法是原生函数,也就是这个方法是用C/C++语言实现的,并且被编译成了DLL,由java去调用。
6.Object类的equals()以及hashcode()
https://blog.csdn.net/zj15527620802/article/details/88547914
首先,正经的Object.equals()是对比两个对象的地址
public boolean equals(Object obj) {
return (this == obj);
}
也就是说如果两个两个object值相等,但是地址不等,也返回false
而在常见的数据类型比较中,a、基本数据类型(e.g., int)是没有equals()方法的,使用的是a==b,比较的是值相等
b、引用数据类型(e.g., Integer),既有方法也有equals()方法。方法比较的是两者地址是否相同,equals()比较的却是两者值是否相同,为何equals()的定义变了呢?因为在这些引用数据类型中,都重写了equals()方法!
需要注意的是当equals()方法被override时,hashCode()也要被override。按照一般hashCode()方法的实现来说,相等的对象,它们的hash code一定相等。
即equals()==true->a.hashcode()==b.hashcode()
,例子如下:
package xuexi1;
public class Main1 {
public static void main(String[] args) {
Integer x1 = new Integer("100");
Integer x2 = new Integer("100");
System.out.println(x1==x2);
System.out.println(x1.equals(x2));
System.out.println(x1.hashCode()+" "+x2.hashCode());
Object x3 = new Object();
Object x4 = new Object();
System.out.println(x3==x4);
System.out.println(x3.equals(x4));
System.out.println(x3.hashCode()+" "+x4.hashCode());
Double x5 = new Double("1.2");
Double x6 = new Double("1.2");
System.out.println(x5==x6);
System.out.println(x5.equals(x6));
System.out.println(x5.hashCode()+" "+x6.hashCode());
}
}
result:
false
true
100 100
false
false
865113938 1442407170
false
true
213909504 213909504
equals()和hashCode()关系:
a.如果两个对象相同,那么它们的hashCode值一定要相同;
b.如果两个对象的hashCode相同,它们并不一定相同(这里说的对象相同指的是用eqauls方法比较)。
如不按要求去做了,会发现相同的对象可以出现在Set集合中,同时,增加新元素的效率会大大下降。
c.equals()相等的两个对象,hashcode()一定相等;equals()不相等的两个对象,却并不能证明他们的hashcode()不相等。
换句话说,equals()方法不相等的两个对象,hashcode()有可能相等(我的理解是由于哈希码在生成的时候产生冲突造成的)。反过来,hashcode()不等,一定能推出equals()也不等;hashcode()相等,equals()可能相等,也可能不等。equals()相同,hashCode()一定相同。
Hashset、Hashmap、Hashtable与hashcode()和equals()的密切关系:搬自https://blog.csdn.net/zj15527620802/article/details/88547914
Hashset是继承Set接口,Set接口又实现Collection接口,这是层次关系。那么Hashset、Hashmap、Hashtable中的存储操作是根据什么原理来存取对象的呢?
下面以HashSet为例进行分析,我们都知道:在hashset中不允许出现重复对象,元素的位置也是不确定的。在hashset中又是怎样判定元素是否重复的呢?在java的集合中,判断两个对象是否相等的规则是:
a.判断两个对象的hashCode是否相等
如果不相等,认为两个对象也不相等,完毕
如果相等,转入2
(这一点只是为了提高存储效率而要求的,其实理论上没有也可以,但如果没有,实际使用时效率会大大降低,所以我们这里将其做为必需的。)
b.判断两个对象用equals运算是否相等
如果不相等,认为两个对象也不相等
如果相等,认为两个对象相等(equals()是判断两个对象是否相等的关键)
为什么是两条准则,难道用第一条不行吗?不行,因为前面已经说了,hashcode()相等时,equals()方法也可能不等,所以必须用第2条准则进行限制,才能保证加入的为非重复元素。
但是这里实现起来有个问题!!!!
比如我创建了一个HashSet类,在插入新元素时,是需要判断是否与已有元素重复的。但是在使用hashCode()和equals()方法判断插入已有元素的对象时,结果都为false,于是能成功插到类中,但是这就和set中不能有重复元素的准则冲突了!为什么呢?因为该HashSet类并没有重写Object的hashCode()和equals()方法,所以只看两个对象的地址是否相同。**解决策略 **在该类中重写该类的hashCode()和equals()方法。
public class Main2 {
public static void main(String[] args) {
Integer x = new Integer("1");
Integer y = new Integer("1");
System.out.println(x.toString());
System.out.println(y.toString());
String x1 = new String("xx");
String y1 = new String("xx");
System.out.println(x1.toString());
System.out.println(y1.toString());
Object m = new Object();
Object m1 = new Object();
System.out.println(m.toString());
System.out.println(m1.toString());
}
}
result:
1
1
xx
xx
java.lang.Object@33909752
java.lang.Object@55f96302
package xuexi1;
public class Main2 implements Cloneable{
int x;
public Main2(int x) {
this.x = x;
System.out.println("this is Main2‘s constructor");
}
@Override
public Main2 clone() throws CloneNotSupportedException {
return (Main2)super.clone();
}
public static void main(String[] args) throws CloneNotSupportedException {
Main2 main2 = new Main2(100);
Main2 main22 = main2.clone(); //复制时不再需要构造函数,直接复制
System.out.println(main22.x);
}
}
result:
this is Main2‘s constructor
100
浅拷贝:拷贝的是同样的地址,引用同一对象
深拷贝:引用不同对象,即A->B,改变A后不会改变B
拷贝的替代方案:拷贝构造函数或拷贝工厂(它们不是真正意义上的clone)
关于proteced:
https://blog.csdn.net/qq_33666602/article/details/104975148
package 1;
public interface Main2{
default void fun() {
System.out.println("Main2.fun()");
}
}
package 1;
public class Main3 implements Main2{
public static void main(String[] args) {
Main2 Example = new Main3();
Example.fun();
}
}
result:
Main2.fun()
注意:抽象类中可以没有抽象方法,可以有普通的属性、方法等;而接口比较严格。
原文:https://www.cnblogs.com/Cindy-H/p/13743926.html