1.数据类型
变量就是申请内存来存储值。也就是说,当创建变量的时间,需要在内存中申请空间。
内存管理体系根据变量的类型为变量分配存储空间,分配的空间只能用来储存该类型数据。
1.1 基本数据类型
Java语言提供了八种基本类型。六种数字类型(四个整数型,两个浮点型),一种字符类型,还有一种布尔型。基本数据类型通常变量申请的内存空间都在栈中申请。
byte:
- byte 数据类型是8位、有符号的,以二进制补码表示的整数;
- 最小值是 -128(-2^7);
- 最大值是 127(2^7-1);
- 默认值是 0;
- byte 类型用在大型数组中节约空间,主要取代整数,由于 byte 变量占用的空间只有 int 类型的四分之一;
- 例子:byte a = 100,byte b = -50。
short:
- short 数据类型是 16 位、有符号的以二进制补码表示的整数
- 最小值是 -32768(-2^15);
- 最大值是 32767(2^15 - 1);
- Short 数据类型也可以像 byte 那样节省空间。一个short变量是int型变量所占空间的二分之一;
- 默认值是 0;
- 例子:short s = 1000,short r = -20000。
int:
- int 数据类型是32位、有符号的以二进制补码表示的整数;
- 最小值是 -2,147,483,648(-2^31);
- 最大值是 2,147,483,647(2^31 - 1);
- 一样平常地整型变量默以为 int 类型;
- 默认值是 0 ;
- 例子:int a = 100000, int b = -200000。
long:
- long 数据类型是 64 位、有符号的以二进制补码表示的整数;
- 最小值是 -9,223,372,036,854,775,808(-2^63);
- 最大值是 9,223,372,036,854,775,807(2^63 -1);
- 这种类型主要使用在需要比较大整数的体系上;
- 默认值是 0L;
- 例子: long a = 100000L,long b = -200000L。
"L"理论上不分巨细写,但是若写成"l"轻易与数字"1"肴杂,不轻易分辩。以是最好大写。
float:
- float 数据类型是单精度、32位、符合IEEE 754标准的浮点数;
- float 在储存大型浮点数组的时间可节省内存空间;
- 默认值是 0.0f;
- 浮点数不能用来表示准确的值,如钱币;
- 例子:float f1 = 234.5f。
double:
- double 数据类型是双精度、64 位、符合 IEEE 754 标准的浮点数;
- 浮点数的默认类型为 double 类型;
- double类型同样不能表示准确的值,如钱币;
- 默认值是 0.0d;
- 例子:
- double d1 = 7D ;
- double d2 = 7.;
- double d3 = 8.0;
- double d4 = 8.D;
- double d5 = 12.9867;
复制代码 7 是一个 int 字面量,而 7D,7. 和 8.0 是 double 字面量。
boolean:
- boolean数据类型表示一位的信息;
- 只有两个取值:true 和 false;
- 这种类型只作为一种标记来记载 true/false 情况;
- 默认值是 false;
- 例子:boolean one = true。
char:
- char 类型是一个单一的 16 位 Unicode 字符;
- 最小值是 \u0000(十进制等效值为 0);
- 最大值是 \uffff(即为 65535);
- char 数据类型可以储存任何字符;
- 例子:char letter = 'A';。
可以通过相应的包装类的内置属性,打印出最大值以及
- public class PrimitiveTypeTest {
- public static void main(String[] args) {
- // byte
- System.out.println("基本类型:byte 二进制位数:" + Byte.SIZE);
- System.out.println("包装类:java.lang.Byte");
- System.out.println("最小值:Byte.MIN_VALUE=" + Byte.MIN_VALUE);
- System.out.println("最大值:Byte.MAX_VALUE=" + Byte.MAX_VALUE);
- System.out.println();
-
- // short
- System.out.println("基本类型:short 二进制位数:" + Short.SIZE);
- System.out.println("包装类:java.lang.Short");
- System.out.println("最小值:Short.MIN_VALUE=" + Short.MIN_VALUE);
- System.out.println("最大值:Short.MAX_VALUE=" + Short.MAX_VALUE);
- System.out.println();
-
- // int
- System.out.println("基本类型:int 二进制位数:" + Integer.SIZE);
- System.out.println("包装类:java.lang.Integer");
- System.out.println("最小值:Integer.MIN_VALUE=" + Integer.MIN_VALUE);
- System.out.println("最大值:Integer.MAX_VALUE=" + Integer.MAX_VALUE);
- System.out.println();
-
- // long
- System.out.println("基本类型:long 二进制位数:" + Long.SIZE);
- System.out.println("包装类:java.lang.Long");
- System.out.println("最小值:Long.MIN_VALUE=" + Long.MIN_VALUE);
- System.out.println("最大值:Long.MAX_VALUE=" + Long.MAX_VALUE);
- System.out.println();
-
- // float
- System.out.println("基本类型:float 二进制位数:" + Float.SIZE);
- System.out.println("包装类:java.lang.Float");
- System.out.println("最小值:Float.MIN_VALUE=" + Float.MIN_VALUE);
- System.out.println("最大值:Float.MAX_VALUE=" + Float.MAX_VALUE);
- System.out.println();
-
- // double
- System.out.println("基本类型:double 二进制位数:" + Double.SIZE);
- System.out.println("包装类:java.lang.Double");
- System.out.println("最小值:Double.MIN_VALUE=" + Double.MIN_VALUE);
- System.out.println("最大值:Double.MAX_VALUE=" + Double.MAX_VALUE);
- System.out.println();
-
- // char
- System.out.println("基本类型:char 二进制位数:" + Character.SIZE);
- System.out.println("包装类:java.lang.Character");
- // 以数值形式而不是字符形式将Character.MIN_VALUE输出到控制台
- System.out.println("最小值:Character.MIN_VALUE="
- + (int) Character.MIN_VALUE);
- // 以数值形式而不是字符形式将Character.MAX_VALUE输出到控制台
- System.out.println("最大值:Character.MAX_VALUE="
- + (int) Character.MAX_VALUE);
- }
- }
复制代码
类型默认值:
1.2 引用数据类型
引用类型是指存储对象或数组的引用(地址),而不是存储实际的值。通过引用,程序可以访问对象或数组的属性和方法。
在 Java 中,主要有以下几种引用类型:
- 对象类型(Object Types):
- 通过类(class)定义的对象属于引用类型。例如:String、ArrayList、用户定义的类等。
- 数组类型(Array Types):
- 数组是一个引用类型,可以存储同一类型的多个值。例如:int[]、String[] 等。
对象或者数组的默认值是NULL。
1.3 基本数据类型之间的转换
整型、实型(常量)、字符型数据可以肴杂运算。
运算中,差别类型的数据先转化为同一类型,然后进行运算。
1.3.1 自动类型转换(隐式转换)
自动类型转换通常发生在如下几种情况中:
- 低精度到高精度的转换,包括:
- byte、short、char 之间的自动提升。
- int、long 之间的自动提升。
- 浮点数从小类型到大类型。
- 非数值类型到数值类型的转换。
- Wrapper类到基本类型的转换。
例如:
- byte b = 10;
- short s = b; // 隐式转换,从 byte 到 short
- int i = s; // 隐式转换,从 short 到 int
- float f = i; // 隐式转换,从 int 到 float
复制代码 在自动类型转换中,你需要注意的是避免由于溢出或精度缺失导致的不精确效果。例如,将一个非常大的整数赋值给一个更小的整数类型可能会导致数据截断。
1.3.2 强制类型转换(显式转换)
显式类型转换通常需要用户明确指定转换的类型,即使用(目标类型)来包裹要转换的表达式或变量。
- 从高精度到低精度的转换。
- 从一个数值类型到另一个数值类型的转换。
- 从数值类型到字符或布尔类型的转换。
例如:
- float f = 10.5f;
- int i = (int) f; // 显示转换,从 float 到 int,结果为 10
复制代码 在强制类型转换中,需要注意的是可能会引起数据丢失。例如,将一个浮点数转换为整数时,浮点数的小数部分会直接被忽略。
隐含强制类型转换
- 1、 整数的默认类型是 int。
- 2. 小数默认是 double 类型浮点型,在定义 float 类型时必须在数字后面跟上 F 或者 f。
1.4 引用数据类型之间的转换
1.4.1 类类型之间的转换
1. 向上转型(Upcasting)
向上转型是指将子类引用赋值给父类引用。这个过程是安全的,由于子类是父类的扩展,父类引用能够包含子类对象。
- class Parent {
- void display() {
- System.out.println("Parent");
- }
- }
- class Child extends Parent {
- void display() {
- System.out.println("Child");
- }
- }
- Parent parent = new Child(); // 向上转型
- parent.display(); // 输出 "Child"
复制代码
在向上转型时,请注意以下几点:
- 不会发生数据丢失。
- 在父类引用中只能访问父类定义的方法和属性,如果需要访问子类特有的方法,需要进行向下转型。
2. 向下转型(Downcasting)
向下转型是指将父类引用赋值给子类引用。这个过程是可能不安全的,由于如果父类引用实际上指向的是一个差别的类型(而不是目标子类的对象),将会引发ClassCastException。
- Parent parent = new Child(); // 向上转型
- Child child = (Child) parent; // 向下转型
复制代码
在向下转型时,需要注意:
- 确保父类引用指向的确实是子类对象,否则会抛出ClassCastException。
- 推荐使用instanceof操作符,返回 true 或者 false 进行检查。
- if (parent instanceof Child) {
- Child child = (Child) parent; // 安全的转换
- }
复制代码
使用instanceof:在进行向下转型之前,使用instanceof可以有效避免转换错误。
1.4.2 接口类型之间的转换
1. 实现接口的类之间的转换
Java答应类实现多个接口,可以在接口之间进行转换。确保实际对象实现了所转换到的接口。如果不实现,转换将失败。
- interface Animal {
- void makeSound();
- }
- class Dog implements Animal {
- public void makeSound() {
- System.out.println("Woof");
- }
- }
- Animal animal = new Dog(); // 向上转型
- Dog dog = (Dog) animal; // 向下转型
复制代码
在接口类型转换时的注意事项:
- 使用instanceof检查对象是否实现了目标接口。
- if (animal instanceof Dog) {
- Dog dog = (Dog) animal; // 安全的转换
- }
复制代码
1.4.3 数组类型转换
Java中的数组也是引用类型,数组类型之间的转换需要注意以下几点:
- 数组的向上转型,例如,将一个String[]引用赋给Object[],是安全的,由于所有数组的父类是Object。
- String[] stringArray = new String[5];
- Object[] objArray = stringArray; // 向上转型
复制代码
- 当进行向下转型时,需要确保实际的数组对象类型与目标类型同等。
- Object[] objArray = new String[5];
- String[] stringArray = (String[]) objArray; // 安全的转换
复制代码 如果尝试将差别类型的数组进行向下转型,会引发ArrayStoreException。
1.4.4 向上转型拿不到子类的特有成员
为何无法通过父类引用访问子类特有的方法?
- 类型擦除(编译阶段):父类引用视图的对象类型是 Animal。即使实际引用的是 Dog,编译器只知道 animal 是一种 Animal,因此只能使用 Animal 类中定义的方法。编译器在编译时只查找 Animal 类的方法,不会考虑 Dog 中的特有方法。
- 静态类型(编译类型)与动态类型(运行类型):
- 静态类型 是指声明变量时的类型(在上面的例子中,animal 的静态类型是 Animal)。
- 动态类型 是指实际引用的对象类型(在这里是 Dog)。
- 由于编译器在编译时仅依赖于静态类型,它无法知道在运行时实际引用的是 Dog,因此只能使用 Animal 的方法。
因此只能通过向下转型来实现访问子类的特有成员。
那为什么访问子类和父类的共同方法,会优先调用子类的方法呢?
- 动态绑定:Java接纳动态绑定(或称晚绑定)来决定在运行时哪个方法应被调用。即使使用父类引用来调用方法,Java会查看实际对象的类型(动态类型)而不是引用类型(静态类型),然后调用实际对象的实现。
1.5 数组
Java 语言中提供的数组是用来存储固定巨细的同类型元素。
创建数组的三种方式:
- dataType[] arrayRefVar = new dataType[arraySize];
复制代码- dataType[] arrayRefVar = {value0, value1, ..., valuek};
复制代码- // new dataType[]{value0, value1, ..., valuek} , 这里的[]不要写大小
- // 因为编译器识别不出{}里面的数据占了多少
- dataType[] arrayRefVar = new dataType[]{value0, value1, ..., valuek};
复制代码
注意事项:
- 数组巨细固定,一旦创建后不能更改,如果需要动态巨细,可以考虑使用 ArrayList 等集合类。
数组常用的方法:
- Arrays.copyOf(数组,指定拷贝长度) 方法进行数组复制。
- Arrays.sort() 方法对数组进行排序。
- Arrays.binarySearch() 方法可以在已排序的数组中查找元素。
- Arrays.toString() 方法,可以将数组转换为字符串
1.6 String、StringBuffer、StringBuild
1. String
- 不可变性:String 对象一旦创建,其内容不可更改。如果对 String 进行修改(比如拼接),会天生一个新的 String 对象,原有字符串保持不变。
- 性能:由于每次修改都需要创建新的对象,频繁操作会导致性能开销较大。
- 线程安全:由于不可变性,String 是线程安全的。
- 使用场景:适合使用在字符串内容不会改变的场合,如常量字符串。
示例:
- String str = "Hello";
- str += " World"; // 生成新的 String 对象
复制代码
2. StringBuffer
- 可变性:StringBuffer 是可变的,意味着在原有对象上实行修改操作时,不会天生新的对象。
- 性能:由于是可变的,在实行较多的字符串操作(如拼接、插入、删除等)时,性能优于 String。
- 线程安全:StringBuffer 是线程安全的,所有方法都是同步的,因此适合在多线程情况中使用。
- 使用场景:适合在多线程情况中进行字符串操作的场合。
示例:
- StringBuffer sb = new StringBuffer("Hello");
- sb.append(" World"); // 修改原有对象
复制代码
3. StringBuilder
- 可变性:与 StringBuffer 类似,StringBuilder 也是可变的,专为字符串操作计划。
- 性能:性能优于 StringBuffer,由于 StringBuilder 的方法不是同步的,它的性能更高。
- 线程安全:StringBuilder 不是线程安全的,不适合在多线程情况中使用。
- 使用场景:适合在单线程情况下进行大量字符串操作。
示例:
- StringBuilder sb = new StringBuilder("Hello");
- sb.append(" World"); // 修改原有对象
复制代码
2.Iterator(迭代器)
2.1 集合实现好的迭代器
Iterator(迭代器)是 Java 集合框架中的一种机制,是一种用于遍历集合(如列表、集合和映射等)的接口。
它提供了一种同一的方式来访问集合中的元素,而不需要相识底层集合的具体实现细节。
Java Iterator(迭代器)不是一个集合,它是一种用于访问集合的方法,可用于迭代 ArrayList 和 HashSet 等集合。
Iterator 是 Java 迭代器最简单的实现,ListIterator 是 Collection API 中的接口, 它扩展了 Iterator 接口。
迭代器接口定义了几个方法,最常用的是以下三个:
- next() - 返回迭代器的下一个元素,并将迭代器的指针移到下一个位置。
- hasNext() - 用于判断集合中是否还有下一个元素可以访问。
- remove() - 从集合中删除迭代器最后访问的元素(可选操作)。
代码演示:
- // 引入 ArrayList 和 Iterator 类
- import java.util.ArrayList;
- import java.util.Iterator;
- public class RunoobTest {
- public static void main(String[] args) {
- // 创建集合
- ArrayList<String> sites = new ArrayList<String>();
- sites.add("Google");
- sites.add("Runoob");
- sites.add("Taobao");
- sites.add("Zhihu");
- // 获取迭代器
- Iterator<String> it = sites.iterator();
- // 输出集合中的所有元素
- while(it.hasNext()) {
- System.out.println(it.next());
- }
- }
- }
复制代码
2.2 自定义迭代器
有一个需求就是普通数据也想用迭代器,那必须得自己封装...
封装迭代器:
- package demo;
- import java.util.Iterator;
- public class MyDataStructure implements Iterable<Integer> {
- private int arr[];
- public MyDataStructure(int[] arr) {
- this.arr = arr;
- }
- @Override
- public Iterator<Integer> iterator() {
- return new MyIterator();
- }
- private class MyIterator implements Iterator<Integer>{
- private int index = 0;
- @Override
- public boolean hasNext() {
- return index < arr.length;
- }
- @Override
- public Integer next() {
- return arr[index++];
- }
- }
- }
复制代码
使用迭代器:
- package demo;
- import java.util.Iterator;
- public class TestIterator {
- public static void main(String[] args) {
- int arr[] = new int[]{11,22,33};
- MyDataStructure mds = new MyDataStructure(arr);
- // 增强for循环
- // for (int num : mds) {
- // System.out.println(num);
- // }
- Iterator<Integer> iterator = mds.iterator();
- while(iterator.hasNext()){
- System.out.println(iterator.next());
- }
- }
- }
复制代码
注意:由于增强For循环也是迭代器实现的,因此也可以使用增强For循环。。。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |