JVM: Java虚拟机,是用来运行Java字节码的虚拟机。
是一种抽象化的计算机,通过在实际的计算机上仿真模拟各种计算机功能来实现的。
JRE:面向程序使用者。Java运行时的环境,包括:Java虚拟机,Java类库,java命令和一些基础构建,不能够创建新程序,只能用于运行程序。
JDK:面向程序开发者。Java开发工具包,提供了编译器javac等工具,能够运行和编写程序。
范围大小: JDK >JRE >JVM
Java语言具有编译和解释两个的特征。Java文件需要先经过编译为字节码文件,再通过解释器执行两个过程。
相同地方:都是面向对象的语言,都支持封装,继承和多态。
不同的地方:
1)Java不提供指针来直接访问内存,程序内存更安全。
2)Java的类是单继承的,C++的类支持多重继承。但是Java的接口是支持多继承的。
3)Java有自动内存管理垃圾回收装机制(GC),不需要手动释放
4)Java只支持方法的重载,不支持操作符重载。
重载和重写的区别:
1)重载:方法名相同,而参数不同,返回值可以相同,也可以不相同。常用于不同的构造器的重载。
2)重写:子类重写父类的方法,外壳不变,里面的东西变了。方法名和形参列表一定要相同,但是返回值也可以不同。
// 注释的内容
/*
*注释的内容
*/
/**
* 文档注释
*
*/
三者都有跳出循环的意思。
方法的返回值:获取到某个方法执行后的结果
方法的类型:有无返回值,有无参数
静态方法为什么不能调用非静态成员?
静态方法属于类,非静态成员属于实例对象。类不能够调用对象的值。当定义为静态成员,则属于类了。
静态方法和实例方法有何不同?
(1)调用方式:静态方法通过类进行调用(类名.方法名); 实例方法需要新建对象,通过实例对象进行调用(对象名.方法名)
(2)访问类成员限制:静态方法只允许访问静态成员(方法和变量);实例方法没有限制。
重载和重写的区别
(1)重载:方法名相同,而参数不同,返回值可以相同,也可以不相同。常用于不同的构造器的重载。
(2)重写:子类重写父类的方法,外壳不变,里面的东西变了。
(3)方法的重写要遵循“两同两小一大”
两同:方法名和形参列表(类型个数顺序均一样)
两小:返回值类型和抛出异常的范围
一大:子类访问权限要比父类大或者相等
1)=-=:因为Java是进行值传递,所以 =-=比较的都是值的大小
基本数据类型:==比较的是值的大小,不同数据类型也是可以的。
引用数据类型:‘’=-=‘’比较的是地址的大小,首先要数据类型相同,且为同一个对象
2)equals() :不能用于基本数据类型,只能为引用数据类型。
(1)不重写:比较两个对象是否为同一个对象。比较地址。等价于‘’=-=‘’
(2)重写:两个对象的属性是否相等。可以不为同一个对象。只需要内部值相同
//1)基本数据类型,==比较的是值是否相等,和数据类型没有关系
int A=1;
double B=1.0;
System.out.println("A==B? "+(A==B)); //true
//2)引用数据类型(类,接口,数组),==比较值的地址,地址相等才会相等
//如果为包装类型的话,会自动拆包和装包,但是一定要在缓存大小内,否则会新建对象
Integer C=1;
int D=1;
System.out.println("C==D? "+(C==D)); //true,自动拆包
Integer E=128;
Integer F=128;
//false:有一个缓存,如果Integer在-128-127之间相等,大于会新建对象
System.out.println("E==F? "+(E==F));
//如果不是一个对象,会进行判错
Integer G=new Integer(1);
Integer H=new Integer(1);
System.out.println("G==H? "+(G==H));
//false:两个引用数据类型不属于同一个对象
//equals比较
//1)首先equals只能对引用数据类型使用,先比较数据类型是否一致,再比较里面的值是否一致,
//可以属于不同的对象(注意:这是重写了equals方法后的性质)
int A=1;
int B=3;
Integer C=3;
//System.out.println(A.equals(C));//报错,不同数据类型不能比较,先判断数据类型,再判断里面的值
System.out.println(C.equals(A+B));//包装类会自动进行转包,转变为包装类
String s1=new String("abc");
String s2=new String("abc");
System.out.println(s1.equals(s2));//先判定数据类型是否一致,再判定内部的值,不比较地址
面试常问问题:
“你重写过 hashCode() 和 equals()么?为什么重写 equals() 时必须重写 hashCode() 方法?”
equals 方法判断两个对象是相等的,那这两个对象的 hashCode 值也要相等。辅助验证(主要是在集合中Map和Set集合中要用到哈希表,查找值快)。hashCode 默认从Object继承来的hashCode是基于对象的ID实现的。不重写,对于同一个对象,可能会不一样。
两个对象有相同的 hashCode 值,他们也不一定是相等的(哈希碰撞)。
hashCode() 和 equals()都是用于比较两个对象是否相等。
1)hashCode() 有什么用?
为了获取哈希码。在哈希表中,通过hashCode()为对象获取哈希码,进而分配地址,便于查找,加快效率。
哈希表能快速找到对象原因:哈希表存储的是键值对(key-value),能根据“键”快速的检索出对应的“值”。这其中就利用到了哈希码!(可以快速找到所需要的对象)
2)JDK 还要同时提供这两个方法?
因为在一些容器中,判断元素是否在容器中,通过hashCode()能够更快进行查找。
3)那为什么不只提供 hashCode() 方法呢?
因为两个对象的hashCode值相等,并不意味着两个对象就相等。优点类似于是重写 equals()的功能。因为多个对象可能存在相同的hashCode值。存在哈希碰撞。
4)如何解决哈希碰撞
开放寻址法:前数组位置1被占用了,就放到下一个位置2上去,如果2也被占用了,就继续往下找,直到找到空位置。
拉链法:链表的方式。在位置上多存一个相同哈希值的地址指向。(尾插法)
5)为什么重写 equals() 时必须重写 hashCode() 方法?
https://www.cnblogs.com/yaobolove/p/5086510.html
因为在Map集合和Set集合中要用到 hashCode() ,如果指的是内容相等,那就要重写
允许在调用方法时传入不定长度的参数。
Java 的可变参数编译后实际会被转换成一个数组。
1.static,修饰类,方法,变量和代码块
1)修饰类:只能够修饰静态内部类,如果修饰外部类,不让编译通过。
2)修饰方法:方法是全局的,不能够被重写。可以被继承和重载。
3)修饰变量:类变量,类加载的时候会进行初始化,只会被创建一次,可以重新赋值。
4)代码块:表示静态代码块,加载类时,会执行代码块,只执行一次。
2. final,可以修饰:类,方法和变量
1)修饰类:那么这个类就是静态的,不能够被继承(String是一个被static final修饰的类)
2)修饰方法:方法是常量的,不能够被重写。可以被继承和重载。
3)修饰变量:即是一个常量,一旦创建不可改变。
3. String是不可变的:String类的值是保存在value数组中的,并且是被private final修饰的。
数据类型分为八种基本数据类型和引用数据类型。
//一:强制类型转换
//1)double 转变为int(不考虑四舍五入)
double double3=20.999999848418418485;
int int2=(int) double3;
System.out.println(int2);
//2)int 转变为 double
long long2=20;
double double2=(double) long2;
System.out.println(double2);
2)四舍五入转换
//二:浮点型转变为整型(考虑四舍五入):一般情况下,int转不下,要用long
double double0=20.999999848418418485;
long int3=Math.round(double0);
System.out.println(int3);
引用数据类型:
定义:进行值地址比较。
种类:类(字符串是一种特殊的类),数组(int[ ];String[ ]),接口(List;Set;Map)
两种类型的区别(需要java中的栈、堆概念):
1)基本数据类型是分配在栈上的,
2)引用类型是分配在堆上的
栈和堆的区别:
使用栈就象我们去饭馆里吃饭,只管点菜(发出申请)、付钱、和吃(使用),吃饱了就走,不必理会切菜、洗菜等准备工作和洗碗、刷锅等扫尾工作,他的好处是快捷,但是自由度小。
使用堆就象是自己动手做喜欢吃的菜肴,比较麻烦,但是比较符合自己的口味,而且自由度大。 (经典!)
包装类:
差别主要在解决问题方式不同:
成员变量:属于类的变量
局部变量:在代码块或或者方法中定义的变量,或者是方法中的参数。
区别主要体现在三方面:
1)语法形式:修饰:成员变量能够被public,private,static 等修饰符所修饰;而局部变量不能;但是两者都能被final修饰
2)存储方式:位置:成员变量被static修饰则属于类,没被修饰则属于实例对象;类和对象都是存储在堆中;局部变量存储在栈中。
3)生存时间:成员变量是对象的一部分,随着对象存在而存在;局部变量属于方法,方法结束就释放内存。
默认值:成员变量有初值,局部变量没有
完成对象的初始化操作
存在默认的构造方法,即无参构造器;
如果申明了构造方法,需要手写无参构造器
面向对象三大特征:封装,继承和多态
继承要注意的额外三点:
1) 子类拥有父类对象所有的属性和方法(包括 私有属性和私有方法),但是子类不能够使用父类私有属性和私有方法,只是拥有。
2)子类拥有自我的属性和方法,在父类基础上拓展。
3)子类可以用自己的方式实现父类的方法。
1)抽象类与普通类相比,就是拥有抽象方法,定义为abstract,其他大部分与普通类相同
(1)抽象方法必须为public或者protected(因为如果为private,则不能被子类继承,子类便无法实现该方法),缺省情况下默认为public。
(2)抽象类不能用来创建对象;
(3)如果一个类继承于一个抽象类,则子类必须实现父类的抽象方法。如果子类没有实现父类的抽象方法,则必须将子类也定义为为abstract类。
2)抽象类与接口相比:接口相当于是全部方法都是抽象方法的抽象类
(1)抽象类可以有默认的方法实现完全是抽象的。接口根本不存在方法的实现
Object 类是一个特殊的类,是所有类的父类
String 类:
定义:使用private static final 关键字修饰字符数组来保存字符串。
StringBuilder 与 StringBuffer :
定义:都继承自 AbstractStringBuilder 类使用字符数组保存字符串,不过没有使用 final 和 private 关键字修饰,提供字符串修改方法。
String不可变原因:
1)保存字符串的数组被 final 修饰且为私有的,并且String 类没有提供/暴露修改这个字符串的方法。
2)String 类被 final 修饰导致其不能被继承
StringBuilder 与 StringBuffer 可变原因:
没有使用 final 和 private 关键字修饰
提供字符串修改方法。
StringBuilder 与 StringBuffer的常用API
1)增加:append(“a”) /insert(index,‘a’)
2)删除:delete(start,end) / deleteCharAt(index)
3)修改:delete(start,end) / deleteCharAt(index)
4)查看:charAt(index)
5)反转:reverse()
StringBuilder string=new StringBuilder();
//1)增加
//(1)在末尾添加
string.append("a");
string.append("b");
string.append("c");
string.append("d");
string.append("e");
System.out.println("原来的="+string);
//(2)在指定位置添加
string.insert(1,"11");
System.out.println("插入后的="+string);
//2)删除
//(1)单个元素,指定位置的元素
string.deleteCharAt(1);
//(2)连续几个元素(start,end) ,采用包前不包后的原则
string.delete(1,3);
System.out.println("插入新的="+string);
//3)修改
string.setCharAt(1, 'z');
//4)查看
char temp=string.charAt(1);
System.out.println("char="+temp);
//5)反转字符串
string.reverse();
System.out.println("反转后的字符串="+string);
参考文章:https://javaguide.cn/
static和final的区别