# 初识数据

# 变量

我们已经学习了最常用的输出语句System.out.println, 想输出东西时可以这样:

System.out.println("something");
System.out.println("something");
System.out.println("something");
System.out.println("something");
System.out.println("something");

输出结果:

something
something
something
something
something

如果我想同时修改这些somethingsome words应该怎么做? 最简单的方法就是直接把它们改成some words即可.
但是这样太麻烦了, 我们可以结合数学里方程的概念, 设一个变量, 输出的是这个变量, 这样只需要改变这个变量的值即可, 就像这样:

String str = "some words";
System.out.println(str);
System.out.println(str);
System.out.println(str);
System.out.println(str);
System.out.println(str);

这样输出的结果就是

some words
some words
some words
some words
some words

你可以认为变量是"临时存放值的场所", 我们可以临时把数据存在这里.
声明变量的方法是 变量的类型 + 空格 + 名称, 后面加一个等号并放入初始值.

# 基本数据类型

Java里总共有8个基本数据类型, 分别是字符类型char, 布尔类型boolean, 数值类型byte、short、int、long、float、double.
数值类型又可分为整数类型byte、short、int、long和浮点数类型float、double.

你可能会有疑问, 为什么数值类型有6种, 而不能只是1种叫number呢?
这是因为声明变量之后, JVM会先在内存里把这个变量要用到的内存空间给占住不让别人动. 就跟你吃馒头一样, 你永远都是先把馒头买到家, 然后再决定怎么吃.
也就是它们的区别在于占用的内存大小不一样, 比如byte只能存-128~127, 如果我写byte b = 129;就会因为byte变量能存的不够那么大而报错(数值溢出错误).

char只能存一个字符, 比如char c = 'a';, 注意Java里对字符串和字符的表示:

String str = "这是字符串"; //用的是英文双引号表示的
char c = 'A';//这是字符, 用的是英文单引号
String str2 = "B"; //字符串也可以是一个单字符
String str3 = ""; //也能是个空字符串

注意StringS是大写, 它不属于基本数据类型, 这是因为String是一个类名, 全名叫做java.lang.String.

基本数据类型不属于类, 你可以发现它们首字母是小写. 同理, int i = 0;i不是对象.
如果你理解不了为什么, 你只需要记住这是一种特殊情况就可以了.

# 数组

如果我有许多int类型的数据, 用什么才可以将它们一起存起来?
你可能想, 有多少创建多少变量不就好了.
如果我不知道有几个呢? 那么只能用数组来存储了.

注意, 数组本质也是一个对象, 但因为理解起来比较抽象, 这里不继续讨论数组是对象的问题了.
多维数组在此处不讨论, 其实本质就是某某类型数组类型的数组, 套娃而已.

int[] nums = new int[3]; //这个数组只能装10个数, 这里的上限最大是int类型的最大值
//数组元素的编号是从0开始的, 所以这三个数字分别是 0号, 1号, 2号
nums[0] = 1;
nums[1] = 666;
nums[2] = 9;
System.out.println(nums[1]); //输出第二个数字

结果是

666

你可以使用nums.length查看数组的总长度(一开始设置的那个数).

你可以这样初始化一个数组:

int[] nums = {1,2,3,666,999,888,444};

这样这个数组的length7, 举个例子, nums[3]666(第四个数).

# 使用变量

public class Demo {    
   public static void main(String[] args){    
      int x=666;    
      System.out.println(x);    
   }    
}    

程序运行后, 会在控制台输出信息如下:

666    

在程序的第三行, 我们定义了一个int类型的变量, 名字叫做x, 初始值为666. 既然是变量, 那么他可以在程序运行时, 在变量的有效范围内, 随时更改它的数值.

public class Demo2 {    
   public static void main(String[] args){    
      int x=666;    
      System.out.println(x);    
      x = 777;    
      System.out.println(x);    
   }    
}    

程序会在控制台中输出如下信息:

666    
777    

“=”符号是赋值符号, 如果想把语句x = 777;写为777 = x;是错误的, 因为“=”符号与数学上的“=”不一样, 赋值符号左面放被赋值的变量名, 右面放需要赋的值.
两个变量之间也可以相互赋值, 例如这样:

int x = 1, y = 2;
// 变量只有里面有数据的时候你才可以使用, 否则会报错
x = y;    
System.out.println(x);    

程序运行后, 在控制台中输出如下信息:

2    

long类型的变量可以存储的最大数字要比int类型更大.
Long.MAX_VAULE代表Long类型可以存储的最大数字, Integer.MAX_VAULE代表int类型可以存储的最大数字. 这也就是说, 在数学上, Long.MAX_VAULE代表的数字要比Integer.MAX_VAULE要大.
long类型的变量与int类型的之间相互赋值, 如果试图把long类型变量内的值赋到int类型的变量当中, 会出现问题.

long a = 2;    
int b = 3;    
b = a;    
System.out.println(b);    

程序会出现问题, 导致程序无法编译.

# 运算

# 加减运算

public class Demo3{  
   public static void main(String[] args){  
      int x=666, y=777;  
      System.out.println(x+y);  
   }  
}  

上面的程序运行后在控制台输出信息如下:

1443

上述程序第三行使用了一种常用的定义变量方式, 这种方式看上去很骚, 并且能同时定义两个int类型的变量, 一个是初始值为666x, 一个是初始值为777y.

但是如果要使用这种方式定义变量, 请警惕下面这种情况:

int x, y = 666;

上面的程序中, 我们定义了两个int类型的变量, 一个是x一个是y. 但是它们的初始值呢?x与y都是666吗?错, x没有初始值, 而y的初始值是666.

上面我们叙述了加法, 同理, 还有减法、乘法和除法.
可能你发现了, 键盘上并没有一个符号是 “×”, 也没有一个符号是“÷”. 想必你已经猜出来了, “*”是乘号, “/”是除号.

# 数字型的乘除运算

public class Demo4{
   public static void main(String[] args){
      int x=8, y=5;
      System.out.println(x/y);
   }
}

我们编写了这样的一个程序. 现在有两个数字, 一个是8, 一个是5, 相比程序运行结果应该是1.6, 而实际情况却与我们想象的结果不一样, 控制台中输出了这样的信息:

1

而我们都知道, 8除以5应当为1.6, 这是怎么回事呢?让我们试试看下面的这个程序:

public class Demo5{
   public static void main(String[] args){
      System.out.println(8.0/5.0);
   }
}

程序运行后, 控制台输出信息如下:

1.6

那我们将“8.0”与“5.0”改为“8”与“5”呢?结果输出了“1”. 这证明, 小数与小数之间的加减乘除与整数与整数之间的加减乘除并不一样. 现在, 我们将不再称呼小数为“小数”, 而要称呼得更加严谨, 即“浮点数”. 整数与整数相除被称作整数除法, 浮点数与浮点数相除被称作浮点除法.
在小学的数学学习中, 我们知道, 被除数与除数相除, 会得到商和余数. 在上面的整数除法中, 8是被除数, 5是除数, 得到的数值1为其商, 这说明, 整数除法计算的结果是商, 而正如我们所见的一样, 浮点数除法得到的是一个确实的浮点数.

public class Demo6{
   public static void main(String[] args){
      System.out.println(7.0/3.0);
   }
}

看上面的这个程序. 在上面的程序中, 我们进行了浮点数相除. 而我们得到的结果并不是无限个3, 而是有限个3. 这说明浮点数除法通常会丢失数据, 我们应当尽可能避免浮点数除法, 或使用更好地方案来计算浮点数相除.

public class Demo7{
   public static void main(String[] args){
      System.out.println(8.1/3);
   }
}

在上面的程序中, 我们可以发现, 有一个数是8.1, 有一个数是3, 一个是整数, 一个是浮点数, 那这是什么神奇的操作呢?其实, 在计算中, 3会被转换为一个浮点数, 所以这个计算仍然是一个浮点数除法计算, 同理, 2.5+3得到的是5.5, 得到的数字是浮点数, 减法与乘法与此相同. 程序最终在控制台输出内容如下:

2.7

byteshortintlong均为整数类型, 区别在于他们能存储的数字大小不一样, byte<short<int<long, 但不能将所有的整数都用long, 我们常用int, 滥用long会无意义的浪费内存空间.
double是一种浮点数类型.
事实上, 8.1就是一个double类型的数据, 3是一个int类型的数据, 在计算过程中会被转换为double类型的3.0. 8.05.0都是double类型的数据, 7.03.0都是double类型的数据. 这也就是说:

int x=6; double y=2.0;
System.out.println(x/y);

在上面的代码里, 我们定义了int类型的xdouble类型的y, 相除过程中将会把x变量中的6转换为double类型的6.0, 6.02.0相除得到3.0, 所以程序在控制台中输出内容如下:

3.0

浮点数与整数相除, 浮点数永远不会被转换为整数, 永远是整数被转换为浮点数.

# 取余运算

刚才我们了解整数除法的时候, 知道了“/”可以取商, 但是怎么取余数呢?用“%”符号, 没错, 就是这个百分号. 就像这样

System.out.println( 8%5 );

在控制台中输出结果如下:

3

这是因为 8÷5=1 …… 3. 一个常用用法是, 利用取余来获得一个数字的个位数字, 例如, 26的个位数字是 26%10, 得到6.

# 隐性转换

long a = 2;    
int b = 3;    
b = a;    
System.out.println(b);    

正如我们刚才所见, 这个程序在刚才的运行中, 出现了问题.
那如果我们想要将int类型变量内的值赋值到long类型的变量当中呢?

long a = 2;    
int b = 3;    
a = b;    
System.out.println(a);    

程序运行后, 会在控制台输出信息如下:

3    

这说明这样做是可行的.
实质上, 在这个过程当中进行了隐性转换. 如上面的程序, 变量b内的数据是int类型的3, 这个数据在赋值入变量a当中时, 会被隐性转换为long类型的3, 然后被赋值入long类型的a.
隐性转换的规则可以理解为“从低等级向高等级”. 我们可以假想为long类型等级比int类型高. 如果这样假想, 那么常见的四个整数类型可以按照这样的方式从低到高排序:
byte < short < int < long

# String类型

# String的使用

String不是基本数据类型, 我们可以用这样的方式声明String对象, 并用一个String的变量把这个对象存起来:

String str = "hello!";

在后面你就会发现, Java里只有String对象的声明方式与其它对象声明方式不一样.

String有加法运算:

System.out.println("Hello" + " " +"world");
//这是三个String对象
//第一个是字符串 Hello
//第二个内容只有一个空格
//第三个是字符串 world
//用加号可以将它们连接起来

输出结果为:

Hello world

String类给出了许多方法, 比如replace方法可以允许你将一个String对象里的所有某个字符串替换成另外一个字符串.
请打开Eclipse试一试. 先在main方法里这样输入:

String str = "test sleeping";
str = str

在这段代码第二行末尾的str后输入一个英文句号, 你会发现Eclipse为你列举出了String类里所有的方法, 这就是IDE的自动补齐代码功能.
我们不理会, 直接继续输入replace, 补全后代码是这样:

String str = "test sleeping";
str = str.replace("sleeping","coding");

请尝试你是否可以使用System.out.println语句将str的内容输出出来.
你应该是这样做:

String str = "test sleeping";
str = str.replace("sleeping","coding");
System.out.println(str);

输出结果:

test coding

# 转义

我们表示字符串都是用双引号括起来的. 那问题来了, 如果字符串的内容里有一个双引号怎么办?

String wrongExample = "会是"这样"吗?" //这可以表示字符串的内容是 会是"这样"吗?  吗?

答案是不可以. 在Java中使用\这样的斜杠代表转义.
在这里简单演示转义的基本用法, 其实还有更多转义的有趣用途, 请在网上自行搜索.

String rightExample = "会是\"这样\"吗?"
String rightExample = "\\";
//用System.out.println输出它们

输出结果

会是"这样"吗?
\

# 查阅JavaDoc

注意replace方法经常会被写错成这样:

// 你应该写 str = str.replace("sleeping","coding");
str.replace("sleeping","coding");

为什么这样不对呢?
因为方法是可以有返回值的, replace方法会把替换后的结果作为返回值返回给我们, 它的返回值是String类型的. replace不会改动原先对象的内容, 只是把新内容返回给我们而已.
所以, 我们要把新内容再赋值给str才可以, 你可以这样试试看:

String str = "test sleeping"
System.out.println(str.replace("sleeping","coding"));
System.out.println(str);

输出结果为:

test coding
test sleeping

那你可能会有疑问, 我是怎么知道的这件事?
答案是, String是Java给出来的一个类, 官方是有说明文档的, 最具有说服力的官方文档就是JavaDoc, 所有官方给出的类都能在这里面找到具体的使用方法.

后续我们开发Bukkit插件时会不断地查阅BukkitAPI的JavaDoc, 不然我们根本不知道该怎么用.
在这里将不继续讲述JavaDoc怎么使用, 后续做Bukkit插件之前会讲述, 这里只是提一下.

# 常量

有些东西我们不希望别人修改, 这些量属于常量.

常量其实就是在变量前加上了final关键字, 这样该常量在设定完毕初始值后将无法再次被更改.

final int finalTest = 1;
finalTest = 2; //修改它会报错

如果该变量前有publicstatic两个关键字修饰, 那么final关键字应该在它们的后面.