JDK和JRE
JDK拥有JRE所拥有的一切,还有编译器(javac) 和工具(如javadoc和jdb)。它能够创建和编译程序。 JRE是Java运行时环境。它是运行已编译Java程序所需的所有内容的集合,包括Java虚拟机(JVM),Java 类库,java命令和其他的一些基础构件。但是,它不能用于创建新程序。
基本数据类型
八个数据类型
基本数据类型可以归为以下四类
①整型
byte 1字节(8位) -128~+127 short 2字节(16位) -32768~+32767 int 4字节(32位) -2147483648~+2147483647 long 8字节(64位) -9223372036854775808~+9223372036854775807 ②浮点型
float 4字节(32位) 10^-38~10^38;有效位数7位 double 8字节(64位) 10^-308~10^308;有效位数15位 ③字符类型
char 2字节(16位) '\u0000'~'\uFFFF';Java中的char是utf-16格式 ④布尔类型
boolean 4字节(32位) true/false 类型转换
除了布尔类型,其他7个类型都可以看作是数值类型,它们之间是可以相互转换的。
箭头方向正常转换,虚线精度可能丢失,实线精度不丢失。箭头反方向强制类型转换,精度大部分情况下会丢失。
数组
⭐java数组中最多可以放多少个元素?
- java数组用int做引索,所以大小受int取值范围(-2147483648~+2147483647)的限制,最大容量2G=2 147 483 639=2^31^个元素空间。
- 同时受“可用内存空间”的大小限制。
- java每个对象元素实际占用内存都大于12字节,即使你有16GB内存,也不够2G个对象。
字符串
除了以上八个基本类型之外,字符串是经常使用的引用类型。
String
⭐String为什么要设立成不可变类?
- 由于 String 在 Java 中是不可变的,这样 Java Runtime 就可以节省大量的 Java 堆空间,因为不同的 String 变量可以在String Pool中引用相同的 String 变量(实际String对象的值)。
- 如果String不是不可变的,那么它将对应用程序造成严重的安全威胁。 例如,数据库用户名,密码作为String传递以获取数据库连接.如果String是可变的,黑客可以轻松改变它的引用值以导致应用程序中出现安全问题。
- 由于String是不可变的,所以它在多线程环境(multithreading)是线程安全的,一个 String 实例可以在不同的线程中共享。 这避免了使用同步(synchronization)来保护线程安全,String是隐式线程安全的.
- String被用在了classloader 类加载器中,不可变性提供了正确的类由Classloader加载的安全性。 例如,假设您尝试加载java.sql.Connection类的实例,但引用的值更改为myhacked.Connection类,可以对数据库执行有害的操作。
- 由于 String 是不可变的,它的 hashcode 在创建时就被缓存了,它不需要再次计算,并且它的处理速度比其他 Object对象要快。这也是为什么 HashMap 常用 String 对象作 key的原因
⭐String为什么是不可变的,以及不可变的好处
- 类本身是final修饰的
- String底层是char数组,数组也是final修饰的,private修饰的
- 整个类没有提供任何一个修改数组内容,以及返回数组引用的方法
StringBuffer
优点:可变对象;线程安全
缺点:所有方法是同步的
StringBuilder
优点:可变对象
缺点:线程不安全安全
创建对象
创建对象的方法:
⭐调用构造函数
①使用new关键字
Student stu=new Student("AGi","男");
②使用Class类的newInstance方法(无参,反射)
Student stu = (Student) Class.forName("com.agi.Student").newInstance(); //com.agi.Student -->Student类路径
③使用Constructor类的newInstance方法(有参无参均可,反射)
Student stu=Student.class.getConstructor().newInstance("AGi","男");
⭐不调用构造函数
①使用clone方法
Student stu2=stu;
②使用反序列化:当我们序列化和反序列化一个对象时,jvm会给我们创建一个单独的对象。为了反序列化一个对象,我们需要让我们的类实现Serializable接口
FileOutputStream fos=new FileOutputStream("object.out"); ObjectOutputStream oos=new ObjectOutputStream(fos); Student student1=new Student("AGi","男"); oos.writeObject(student1); oos.flush(); oos.close(); FileInputStream fis=new FileInputStream("object.out"); ObjectInputStream ois=new ObjectInputStream(fis); Student student2=(Student) ois.readObject(); System.out.println(student2);
⭐除了第1个方法,其他4个方法全都转变为invokevirtual(创建对象的直接方法),第一个方法转变为两个调用,new和invokespecial(构造函数调用)。
泛型
⭐Java泛型了解么?什么是类型擦除?
Java泛型(generics) 是JDK5中引入的一个新特性,泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型。泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。 Java的泛型是伪泛型,这是因为Java在编译期间,所有的泛型信息都会被擦掉,这也就是通常所说类型擦除。
==和equals区别
⭐ ==
它的作用是判断两个对象的地址是不是相等。即判断两个对象是不是同一个对象。 (基本数据类型比较的是值,引用数据类型比较的是内存地址)
⭐equals()
它的作用也是判断两个对象是否相等,它不能用于比较基本数据类型的变量。equals()方法存在于0bject类中,而0bject类是所有类的直接或间接父类。
hashCode()和equals()
⭐hashCode()
hashCode()的作用是获取哈希码,也称为散列码;它实际上是返回一个int整数。这个哈希码的作用是确定该对象在哈希表中的索引位置。hashCode()定义在JDK的0bject类中,这就意味着Java中的任何类都包含有hashCode()函数。另外需要注意的是: 0bject的hashcode方法是本地方法,也就是用C语言或C++实现的,该方法通常用来将对象的内存地址转换为整数之后返回。
⭐为什么重写equals()要重写hashcode()
我们重写了某个类的equals方法,使用该类实例化了两个对象,给他们的成员变量赋的是一样的值,使用equal方法比较两个对象返回true;把两个对象放到set集合里面,打印set发现两个对象都被打印出来了;显然这个结果是不对的,因为set里面的元素不重复,他们使用equals比较返回的是true,明明一样,放到set里面为什么不能去重成功呢?因为set是根据hashCode()来判断是不是同一个对象,这个类没有重写hashCode(),默认值是内存地址,新创建的两个对象内存地址不一样,所以去重不成功。