Java SE 基础
Java概述
Java简介
Java 作为一种面向对象的高级语言,一方法Java 语言的语法与 C 语言和 C++ 语言很接近,使得大多数人很容易学习和使用。另一方面,Java 摒弃了 C++ 中操作符重载、多继承、自动的强制类型转换。特别地,Java 语言不使用指针,而是引用。与此同时提供了自动分配和回收内存空间,使得我们不必为内存管理而担忧。目前Java分为三个体系:
Java SE(Java 2 Platform Standard Edition,Java平台标准版)
Java EE(Java 2 Platform,Enterprise Edition,Java平台企业版)
Java ME(Java 2 Platform Micro Edition,Java平台微型版)
Java特性
Java 语言是面向对象的:
Java 语言提供类、接口和继承等面向对象的特性,为了简单起见,只支持类之间的单继承,但支持接口之间的多继承,并支持类与接口之间的实现机制。Java 语言全面支持动态绑定,而 C++语言只对虚函数使用动态绑定。总之,Java语言是一个纯的面向对象程序设计语言。
Java语言是跨平台的:
Java的跨平台性,是通过不同系统都有对应的JVM(Java虚拟机)实现的,java程序只需要一次编译成class文件,就可实现跨平台执行。实际上就是不同系统的JVM把class文件都解释成相同的意思,从而实现了跨平台。
Java语言是安全的:
Java通常被用在网络环境中,为此,Java 提供了一个安全机制以防恶意代码的攻击。除了Java 语言具有的许多安全特性以外,Java 对通过网络下载的类具有一个安全防范机制,分配不同的名字空间以防替代本地的同名类、字节代码检查,并提供安全管理机制让 Java 应用设置安全哨兵。
Java 语言是支持多线程的:
在 Java 语言中,线程是一种特殊的对象,它必须由 Thread 类或其子类来创建。通常有两种方法来创建线程:其一,使用型构为 Thread(Runnable) 的构造子类将一个实现了 Runnable 接口的对象包装成一个线程,其二,从 Thread 类派生出子类并重写 run 方法,使用该子类创建的对象即为线程。值得注意的是 Thread 类已经实现了 Runnable 接口,因此,任何一个线程均有它的 run 方法,而 run 方法中包含了线程所要运行的代码。线程的活动由一组方法来控制。Java 语言支持多个线程的同时执行,并提供多线程之间的同步机制。
Java的运行机制
当我们编写一个HelloWorld.java的文件后,使用“Javac HelloWorld.java”命令使Java编译器对其进行编译。编译结束后会自动生成一个HelloWorld.class的字节码文件。Java虚拟机首先将编译好的字节码文件加载到内存,这个过程被称为类加载,它是由类加载器完成的,然后虚拟机针对加载到内存中的Java类进行解释执行,之后我们便可看到运行结果。
Java基础语法
我们不妨用Java写一个最经典的“Hello World"程序来进入我们Java的学习。
public class HelloWorld{
public static void main(String[] args) {
System.out.println("Hello World");
}
}
现在我们可能对图上的一些关键字还并不了解其作用,但这并不影响我们学习Java,至少这一段代码让我们对Java编写程序时的结构有了一定的认识。之后我们也会按照这样的结构来学习并运用Java。
基本注意事项
当我们编写Java程序时,应该注意以下几点:
- JAVA代码由功能性语句和结构性语句组成,结构性行语句主要是为了承载功能性语句
- 大小写敏感:Java 是大小写敏感的,这就意味着标识符 Hello 与 hello 是不同的
- 类名:对于所有的类来说,类名的首字母应该大写。如果类名由若干单词组成,那么每个单词的首字母应该大写,例如MyFirstJavaClass
- 方法名:所有的方法名都应该以小写字母开头。如果方法名含有若干单词,则后面的每个单词首字母大写。
- 源文件名:源文件名必须和类名相同。当保存文件的时候,你应该使用类名作为文件名保存(切记 Java 是大小写敏感的),文件名的后缀为.java(如果文件名和类名不相同则会导致编译错误)。
- 主方法入口:所有的 Java 程序由 public static void main(String[] args) 方法开始执行
标识符和修饰符
Java 所有的组成部分都需要名字。类名、变量名以及方法名都被称为标识符。所有的标识符都应该以字母(A-Z 或者 a-z),美元符、或者下划线开始首字符之后可以是字母(A-Z 或者 a-z),美元符、下划线或数字的任何字符组合。关键字不能用作标识符。
像其他语言一样,Java可以使用修饰符来修饰类中方法和属性。主要有两类修饰符:
访问控制修饰符 : default, public , protected, private
非访问控制修饰符 : final, abstract, static
我们之后会继续深入学习Java中修饰符的作用。
基本数据类型
Java语言提供了八种基本类型。六种数字类型(四个整数型,两个浮点型),一种字符类型,还有一种布尔型。
基本类型 | 二进制位数 | 最大值 | 最小值 |
---|---|---|---|
byte | 8 | 127 | -128 |
short | 16 | 32767 | -32768 |
int | 32 | 2147483647 | -2147483648 |
long | 64 | 9223372036854775807 | -9223372036854775808 |
float | 32 | 3.4028235E38 | 1.4E-45 |
double | 64 | 1.7976931348623157E308 | 4.9E-324 |
char | 16 | 65535 | 0 |
boolean | / | / | / |
变量:用于存储数据,主要包括变量名和相应内存
使用特点:声明变量时候要指定变量的数据类型,赋值时候需要相互匹配
整数:byte short int long
常量和变量都是需要存储空间,没有带L的常数,占据的存储空间是4字节
浮点数:float和double,不带符号的浮点数常量存储类型为double(可以使用float或者double存储int类型 short byte)
字符:占据两个字节,一定范围内的整数可以直接赋值给字符变量 取出来的时候仍然会以字符的形式进行
字符类型:char 布尔类型:boolean
数据类型转换和作用域
自动类型转换:
第一:数据类型兼容
第二:目标的存储空间不小于源存储空间
强制类型转换:强制类型可能会发生数据精度的丢失,因为存在数据空间截取的问题
变量的作用域:大括号会限制变量的作用域
运算符
算术运算符
算术运算符运用在数学表达式中,它们的作用和在数学中的作用一样,这一点应该不必去纠结。唯一需要去注意的是自增(++)自减(–)运算符是一种特殊的算术运算符,在算术运算符中需要两个操作数来进行运算,而自增自减运算符是一个操作数。这种自增自减运算有两种不同的方法去实现。
前缀自增自减法(++a,–a): 先进行自增或者自减运算,再进行表达式运算。
后缀自增自减法(a++,a–): 先进行表达式运算,再进行自增或者自减运算。
实例:
public class selfAddMinus{
public static void main(String[] args){
int a = 5;
int b = 5;
int x = 2*++a;
int y = 2*b++;
System.out.println("自增运算符前缀运算后a="+a+",x="+x);
System.out.println("自增运算符后缀运算后b="+b+",y="+y);
}
}
上述程序运行结果如下:
关系运算符和赋值运算符
关系运算符也是我们老生常谈的问题了,它用于我们对两个数据进行比较,这里就不细谈了。赋值运算符我们也见的多了,值得注意的是,像+=等这些复合赋值运算,会将自动类型转换自我完成,使用普通的表达式的话,需要程序显式转换。
逻辑运算符
下表列出了逻辑运算符的基本运算,假设布尔变量A为真,变量B为假
操作符 | 描述 | 例子 |
---|---|---|
&& | 称为逻辑与运算符。当且仅当两个操作数都为真,条件才为真。 | (A && B)为假 |
|| | 称为逻辑或操作符。如果任何两个操作数任何一个为真,条件为真 | (A||B)为真 |
! | 称为逻辑非运算符。用来反转操作数的逻辑状态。如果条件为true,则逻辑非运算符将得到false | ! (A && B)为真 |
短路逻辑运算符
当使用与逻辑运算符时,在两个操作数都为true时,结果才为true,但是当得到第一个操作为false时,其结果就必定是false,这时候就不会再判断第二个操作了。
实例运用1:电脑库存清单
public class StoreInventorylist {
public static void main(String[] args) {
//Mac
String macBrand = "MacBookAri";
float macSize = 13.3f;
double macPrice = 6988.88;
String macConfig = "i5 processor 4GB ram 128G SSD";
int macStock = 5;
//Thinkpad
String thinkpadBrand = "Thinkpad450";
float thinkpadSize = 14.0f;
double thinkpadPrice = 5999.99;
String thinkpadConfig = "i5 processor 4GB ram 500G SSD";
int thinkpadStock = 10;
//ASUS
String asusBrand = "Thinkpad450";
float asusSize = 15.6f;
double asusPrice = 4999.5;
String asusConfig = "i7 processor 4GB ram 128G SSD";
int asusStock = 18;
int totalStock = macStock + thinkpadStock + asusStock;
double totalAmout = macPrice*macStock + thinkpadPrice*thinkpadStock + asusPrice*asusStock;
System.out.println("--------------- Store Inventory list ---------------------------");
System.out.println("Brand Size Price Config Stock");
System.out.println(macBrand+" "+macSize+" "+macPrice+" "+macConfig+" "+macStock);
System.out.println(thinkpadBrand+" "+thinkpadSize+" "+thinkpadPrice+" "+thinkpadConfig+" "+thinkpadStock);
System.out.println(asusBrand+" "+asusSize+" "+asusPrice+" "+asusConfig+" "+asusStock);
System.out.println("----------------------------------------------------------------");
System.out.println("Total Stock:" + totalStock);
System.out.println("Total Amout:" + totalAmout);
}
}
此程序只是为了我们更好的了解基础数据类型,声明变量时要指定变量的数据类型,赋值需要相互匹配,并且内存空间一定要保证足够,否则会发生精度缺失。上述程序运行结果如下:
选择结构语句
if条件语句:
-
if:当布尔值为true 执行代码块
-
if else:具有两个代码块 条件为true执行语句块1 条件为false执行语句块2
-
三元表达式具有和if else同等的效果 都具有三元素 条件判断 语句1 语句2
-
if else if else:
if是必须的 后两者都不是必须的
switch条件语句:
-
switch中的可以是表达式 ,变量,常量,switch的数据类型可以是byte char short int String
-
使用case中的目标值进行切入点的匹配,使用break语句进行switch结构的推出
-
case后面的需要是常量,不能够是变量
循环结构语句
while:
和if条件语句类似 不同在于执行完代码块之后 会继续进行条件判断循环往复
do while:
和while类似,区别在于第一次代码块的执行是无条件
for:
初始表达式:只执行一次 任意一条Java语句都可以
循环表达式:每次执行循环体之前都要执行 可以是表达式 变量 常量(布尔值)
操作表达式:循环体结束之后进行运行 ,运行之后再进行循环条件的判断,任意一条Java语句
初始表达式:操作表达式可以不写,但是两个分号不能省
循环嵌套:循环体中的代码可以是循环结构,从而形成嵌套循环
break:
可以结合switch和循环结构,和循环体结合的时候会终止循环,直接运行循环后面的程序
嵌套循环时候,一般情况下退出内层循环,就近原则
需要退出嵌套循环中的外层循环,需要额外的操作
continue:
可以和循环体结合使用用于退出本次循环,并不会直接跳转到循环体外
实例运用2:猜数字
import java.util.Random;
import java.util.Scanner;
public class RandomNum {
public static void main(String[] args){
Random random=new Random();
int randomNum=random.nextInt(10);
Scanner scanner=new Scanner(System.in);
int myNum;
do {
System.out.println("please input a number:");
myNum=scanner.nextInt();
if(myNum>randomNum){
System.out.println("输入值偏大!");
}else if(myNum<randomNum){
System.out.println("输入值偏小");
}else {
System.out.println("猜测正确:"+randomNum);
}
}while (myNum!=randomNum);
}
}
我们用上述程序可以实现简单的猜数字游戏,通过编写这种程序可以加深我们对于选择结构和循环结构的理解。
方法
Java方法是语句的集合,它们在一起执行一个功能。最常见的就是我们之前运用的最多的System.out.println(),这句话的用法是调用系统类 System 中的标准输出对象 out 中的方法println()
方法包含一个方法头和一个方法体。下面是一个方法的所有部分:
- 修饰符:修饰符,这是可选的,告诉编译器如何调用该方法。定义了该方法的访问类型。
- 返回值类型 :方法可能会返回值。returnValueType
是方法返回值的数据类型。有些方法执行所需的操作,但没有返回值。在这种情况下,returnValueType 是关键字void。 - 方法名:是方法的实际名称。方法名和参数表共同构成方法签名。
- 参数类型:参数像是一个占位符。当方法被调用时,传递值给参数。这个值被称为实参或变量。参数列表是指方法的参数类型、顺序和参数的个数。参数是可选的,方法可以不包含任何参数。
- 方法体:方法体包含具体的语句,定义该方法的功能。
我们不妨用一张图来更好的理解Java中的方法:
方法的使用大大提升了开发代码的效率,使程序变得更简短而清晰,提高了代码的重用性,也有利于程序维护。
数组
数组对于每一门编程语言来说都是重要的数据结构之一,在Java 语言中提供的数组是用来存储固定大小的同类型元素的。当然我们也经常对数组里的数据进行遍历来实现提取数据。因为数组的元素类型和数组的大小都是确定的,所以当处理数组元素时候,我们通常使用基本循环或者 For-Each 循环。
在这里我也就不作过多分析解读了,在之后的学习中运用起来就好了。
实例运用3:随机点名器
import java.util.Random;
import java.util.Scanner;
public class RandonClass {
public static void addStudents(String[] students){
Scanner scanner=new Scanner(System.in);
for(int i=0;i<students.length;i++){
students[i]=scanner.next();
}
}
public static void allStudent(String[] students){
for(String student:students){
System.out.println(student);
}
}
public static void randonStudent(String[] students){
Random random=new Random();
int num=random.nextInt(students.length);
System.out.println("随机点名到的同学为:"+students[num]);
}
public static void main(String[] args){
String[] students=new String[5];
addStudents(students);
System.out.println();
allStudent(students);
System.out.println();
randonStudent(students);
}
}
同样的我们利用上述程序巩固了我们对于方法和数组运用的能力。特别是我们如何创建、初始化和操纵数组。(BTW,在所有程序中所引用的库可以去官方文档查看其源码和此库所实现的功能)