Java学习笔记(一)

因为已经学过挺多编程语言了,加上我最熟悉的还是C/C++,所以Java基础的部分,就只记录和 C/C++ 的不同了,相同的部分我就快速过了

基本数据类型

数据类型 取值范围 内存占用(字节数)
byte -2^7 ~ 2^7-1 1
short -2^15 ~ 2^15-1 2
int -2^31 ~ 2^31-1 4
long -2^64 ~ 2^64-1 8
float 32位 单精度 IEEE754 浮点数 4
double 64位 双精度 IEEE754 浮点数 8
boolean true| false 1
char 0 ~ 2^16-1(\u0000 ~\uffff) 2

类型转换

低  ------------------------------------>  高
byte,short,char—> int —> long—> float —> double

和 C/C++ 的异同

  • java 除了 char 都是有符号类型,没有 unsigned int 之类的无符号类型
  • 布尔型叫做 boolean 而不是 bool
  • java 里的 long 等价于 C++ 里的 long long 而非 long
  • char 是 2 个字节而非 1 个字节,因此 java 的 char 可以存储汉字例如 '中'
  • 其实 C/C++ 的 char 是分有符号和无符号的,有 signed char 、 unsigned char 和 char 三种,char 大多编译器似乎是有符号的,部分编译器是无符号的,java 的 char 只有无符号的
  • 多了一个 byte 类型,比 short 还小
  • Java 的隐式或者说自动类型转换只能从容量小的向容量大的转换
  • java 的 boolean 无法进行类型转换,无论是否强制(显式)类型转换
  • 和 C/C++ 相同的是这些类型在进行运算时会自动跃升成高等级的,等级参考上面的类型转换,但是由于 java 自动类型转换不能转换成低容量的类型,因此 byte、short、char 运算的结果(哪怕同类型运算)在不强制类型转换的情况下,只能赋值给 int 或者更高容量的类型
  • 其余基本和 C/C++相同,比如整数默认 int,小数默认 double 之类的

运算符

java 有引用类型 String,也就是字符串,不同于C/C++ 的字符串常量默认是个字符常量数组,而 java 字符串默认就是 String 类型,因此 java 的字符串可以直接使用 + 当作连接运算符,且连接运算时可以自动把其他类型当成字符串来运算,包括无法类型转换的 boolean

这个 String 和 C++ STL中的 String 类似,但最大的区别就是 java 的字符串常量默认是 String 而 C++ 因为 C 的缘故只能是字符常量数组

java 和 C/C++ 的运算符的规则基本上是相同的(不考虑 C/C++ sizeof、::之类的运算符,只考虑基础的算术、逻辑、关系、位、赋值运算符的话)

数组

数组这里开始 Java 和 C/C++ 区别就大了不少,Java 中的数组和 C/C++ 中的数组有着本质的不同,Java 中的其实是一切皆对象的,所以 Java 中的数组是一个类,而 C/C++ 的数组是一种数据结构,因此 Java 里的数组名就是个对象,而 C/C++ 的数组名则指代了数组这种数据结构

再看数组的定义方式,java 的数组有两种初始化的方式,且两者不能混用(不初始化就和其他引用类型一样,默认是 null )

一种是静态初始化的方式,也就是在定义的同时初始化数组元素

//dataType[] arrayRefVar = {value0, value1, ..., valuek};
double[] arr = new double[]{1.1, 2.4, 0.5, 100.45};
​
//简写形式
double[] arr = {1.1, 2.4, 0.5, 100.45};

另一种方式就是动态初始化,就是在定义的时候只指定数组长度,而不指定元素初始的值,此时元素的初始值为默认值,比如 int、char 是 0,double是 0.0,string 之类的引用类型就是 null

//dataType[] arrayRefVar = new dataType[arraySize];
double[] arr = new double[4];

第一个明显的不同是 Java 定义数组时,数组的中括号是写在类型后面,变量前面的,虽然也可以写成 C/C++ 那种在变量后面,不过不被推荐,且这个中括号里是不能写数字的,只是单纯的表示这是个数组

第二个就是初始化是通过 new 出来的的,而不是直接一个大括号(直接大括号也只是个简写罢了),因为 Java 的数组是个类,这里的 new 和 C++ 的 new很接近,没错,就是动态分配时候用的那个,因此 Java 的数组里的元素和 C++ 动态分配出来的一样,都是存储在堆里的,而不是在栈或者全局/静态变量区之类的地方

我们经常觉得 C/C++ 的数组有点像指针,但本质上还是有区别的,但 Java 里的数组其实更接近 C/C++ 中的指针,Java 的数组就像指针一样存储的只是一个地址,而且可以像指针一样通过赋值来使多个数组名指向同一个数组,也就是所谓的浅拷贝

Java 中的引用类型,其实可以看成是个有一定约束的 C/C++ 的指针

正常来说应该这里是到函数或者在 Java 的方法,不过因为这东西和 C/C++ 的几乎一样,唯一区别可能就是 Java 没有默认参数这个特性

前面提到过,Java 是万物皆对象的,而且 Java 没有指针的概念,因为 Java 的引用类型,就是类似指针的存在,只不过 Java 会自动帮你回收,而不像 C/C++ 那样需要自己管理,所以 Java 中的对象只能通过 new 的方式创建,Java 中的对象的存在也类似于 C++ 中的对象指针

public class Puppy{
   public Puppy(String name){
      //这个构造器仅有一个参数:name
      System.out.println("小狗的名字是 : " + name ); 
   }
   public static void main(String[] args){
      // 下面的语句将创建一个Puppy对象
      Puppy myPuppy = new Puppy( "tommy" );
   }
}

其他方面就和 C++ 大同小异了,比如和类同名的函数是构造函数或者说方法,类的内部可以通过 this 访问当前的对象等等

不同之处也有一些,比如以下几点:

  • Java 因为没有指针的概念,访问成员变量和成员函数就没有 -> 这种运算符了,都是用 . 来访问了
  • Java 初始化成员变量是没有初始化列表这个东西的,只能通过构造函数或者直接声明的时候初始化(C++11以后支持声明时初始化)
  • 又由于 Java 没有指针,所以 Java 也没有移动构造之类的东西
  • Java 类中的成员变量和方法默认不是 private,而是介于 private 和 protected 之间,可以称为 default
  • Java 中的修饰符不能像 C++ 那样同时作用多个,而是需要每个成员方法和变量前都要加,不加就是上一条说的 default

String

Java 的 String 类型和 C++的 String 非常类似,但由于 Java 本身类的一些限制,所以还是有一些差异

首先字符串常量上,Java 的字符串常量都是存在堆中的字符串常量池里,而 C++ 的常量也是在专门的常量存储区

如果直接把字符串常量赋值给 String 类型的变量,Java 的话是类似于 C++ 的字符常量指针,直接指向常量池中的地址,而 C++ 里则是会拷贝一份到栈中

但如果一旦进行运算,Java 里的 String 就会再创建一个新的字符串在堆中,而不是常量池中的那个了,因为常量池中的字符串常量是不可修改的,且通过构造函数(或者说 new)创建的 String 对象也不会再指向常量池中的字符串常量,即便是通过字符串常量来构造的

由于 Java 中虽然有方法重载,但是没有运算符重载,所以 Java 中引用类型的比较都是在比较地址,因此 Java 中字符串的比较如果直接用 == 不一定能得到想要的结果,同样的也不能像数组那样来访问某个字符,因为 C++ 的 String 是通过重载下标运算符实现的(Java 的String 除了可以用 + 来连接,其他运算符都不行)

下面是一些 Java String 类常用的方法,还有很多,反正需要的时候查文档就行

int length()// 返回此字符串的长度
char charAt(int index) // 返回指定索引处的 char 值
boolean equals(Object anObject) // 将此字符串与指定的对象比较
boolean equalsIgnoreCase(String anotherString)// 将此 String 与另一个 String 比较,不考虑大小写
char[] toCharArray()// 将此字符串转换为一个新的字符数组
String substring(int beginIndex)// 返回一个新的字符串,它是此字符串的一个子字符串
String substring(int beginIndex, int endIndex)// 返回一个新字符串,它是此字符串的一个子字符串
boolean startsWith(String prefix)// 测试此字符串是否以指定的前缀开始
boolean contains(CharSequence chars)// 判断是否包含指定的字符系列
String[] split(String regex)// 根据给定正则表达式的匹配拆分此字符串

ArrayList

因为 Java 中的数组大小固定,不可变化,虽然 C/C++ 也是,但可以通过指针动态分配来实现可变数组,C++ STL 也有 Vector 这个类,而 Java 中也有个类似的类,就是 ArrayList

和 C++ 的 Vector 有个区别就是 ArrayList(集合) 可以不限类型,里面可以放多种类型的元素,但是我们一般还是限定类型,通过泛型(有点类似 C++ 的模板,但作用不太一样)来限制类型,但泛型只能使用引用类型(基本类型有封装好的引用类型),且只是作用于编译阶段

ArrayList list = new ArrayList()  // 不限制类型
ArrayList<String> list = new ArrayList<String>();// 限制类型为 String
ArrayList<String> list = new ArrayList<>();// 简写,<>好像也能省略

集合添加元素可以使用 add 方法

arr.add("a")    // 添加到末尾
arr.add(3,"a")  // 添加到第四个元素前面,后面的往后移

访问使用 get 方法,修改使用 set,删除使用 remove,查看大小用 size

arr.get(1)          // 访问第二个元素
arr.set(2, "Wiki")  // 修改第三个元素
arr.remove(3)       // 删除第四个元素,后面的元素往前移
arr.remove("Wiki")  // 删除第一个 "Wiki",后面的元素往前移
arr.size()

如果使用 Integer 类型(int 类型的引用类型版)的 ArrayList 通过元素值来删除时,需要先转换成 Integer 类型,否则使用的是索引删除