1、环境搭建
Java SE(Standard Edition,Java标准版),是Java的核心版本,其中包括Java面向对象、JVM、API等功能。在此基础上的Java EE(Enterprise Edition,Java企业版)是面向企业的版本,其中包括JSP、EJB、Service等功能,Java ME(Mobile Edition,Java移动版)主要用于嵌入式开发,包含移动设备、游戏、通信等功能。
JVM(Java Virtual Machine,Java虚拟机),是Java实现跨平台开发的核心。我们编写的源文件是以.java结尾的,通过编译器编译为.class结尾与平台无关的二进制字节码文件,之后通过JVM中的解释器将字节码文件翻译为可执行文件。
JDK(Java Development Kit,Java开发工具包)包括Java开发所需的一些列程序包。JRE(Java Runtime Environment,Java运行环境)包含运行Java程序所需要的环境。JDK包含JRE,JRE包含JVM。
安装配置
从Oracle官网:http://www.oracle.com/technetwork/java/javase/downloads 下载所需的Java版本的JDK,并且选择对应的操作系统,例如我选择Java 8,并且在64位Windows系统运行。
下载之后是一个可执行文件,一路点击安装,完成后jdk的文件目录如下图所示,其中bin目录下是一些可执行文件,例如java.exe、javac.exe。lib文件夹下是一些Java开发时需要的类库文件,以.jar结尾。
安装之后需要对环境变量进行配置,第一个环境变量是JAVA_HOME,对应JDK的安装位置。第二个是修改PATH变量的值,在其中添加bin目录下可执行文件位置,这样在系统中其他位置也可以执行Java命令。第三个是CLASSPATH对应开发所需类库即lib的位置,在jdk1.5版本之后JRE能自动搜索目录下类文件,找到 JDK目录下lib文件夹中的.jar文件,因此不需要再配置CLASSPATH。
环境变量位置:右击我的电脑->属性->高级系统设置->环境变量->系统变量,点击新建JAVA_HOME如下左图所示,变量值为jdk的安装目录。在系统变量中找到PATH,双击弹出编辑PATH环境变量,选择新建,添加两个系统环境变量如下右图所示
配置成功后在Windows命令行下输入java、javac命令可以看到相应的提示信息。
编译运行
编写一个简单的Java源文件HelloWorld.java如下,
public class HelloWorld{
public static void main(String[] args){
System.out.println("Hello Java!");
}
}
在文件HelloWorld.java文件目录下执行命令:javac HelloWorld.java,生成字节码文件HelloWorld.class
通过命令运行字节码文件: java HelloWorld,输出Hello Java!
2、基础知识
变量
标识符可以由字母、数字、下划线(_)、美元符($)组成,但不能包含 @、%、空格等其它特殊字符,不能以数字开头,标识符是严格区分大小写的。标识符不能是 Java 关键字和保留字,如下所示
Java 语言是一种强类型语言。通俗点说就是,在 Java 中存储的数据都是有类型的,而且必须在编译时就确定其类型。
Tips:0的ASCII码是48,A的ASCII码是65,a的ASCII码是97
Java默认类型的长度如下:
-
byte:1个字节 8位 -128~127
-
char:2个字节
-
short :2个字节 16位
-
int :4个字节 32位
-
long:8个字节 64位
-
float:4个字节 32 位
-
double :8个字节 64位(Java默认的是double类型,如3.14是double类型的,加后缀F(3.14F)则为float类型的)
例如int有32位,那么其表示数的范围为-2^31~2^31-1,其最大值为0x80000000(2147483647)
对于一份规范的程序源代码而言,注释应该占到源代码的 1/3 以上。Java 中注释有三种类型:单行注释、多行注释、文档注释。可以通过 javadoc 命令从文档注释中提取内容,生成程序的 API 帮助文档,使用文档注释时还可以使用 javadoc 标记,生成更详细的文档信息:
数组
注意Java中数组的初始化使用的是{}
int[] scores; // 声明数组,中括号放在变量类型后
int scores[]; // 声明数组,中括号放在变量名后
scores=new int[5]; // 为数组变量分配存储空间
int[] scores=new int[5]; // 可以合并声明与分配两个步骤
int[] scores={1,2,3,4,5}; // 声明、分配与初始化数组,注意[]为空
int[] scores=new int[]{1,2,3,4,5};
int[][] points = {{10, 16}, {2, 8}, {1, 6}, {7, 12}}; //声明二维数组
Arrays类的使用
import java.util.Arrays; //导入Arrays类
public class HelloWorld {
public static void main(String[] args) {
// 定义一个字符串数组
String[] hobbies = { "sports", "game", "movie" };
// 使用Arrays类的sort()方法对数组进行排序
Arrays.sort(hobbies);
// 使用Arrays类的toString()方法将数组转换为字符串并输出
System.out.println( Arrays.toString(hobbies));
//fill()方法可以对数组进行统一填充
Arrays.fill("str");
}
}
通过如下方法可以对数组进行拷贝,其参数含义为(原数组, 原数组的开始位置, 目标数组, 目标数组的开始位置, 拷贝个数)
public static native void arraycopy(Object src, int srcPos, Object dest, int desPos, int length)
二维数组的使用:
public class HelloWorld {
public static void main(String[] args) {
// 定义两行三列的二维数组并初始化
String[][] names={{"tom","jack","mike"},{"zhangsan","lisi","wangwu"}};
// 通过二重循环输出二维数组中元素的值
for (int i = 0; i < names.length ; i++) {
for (int j = 0; j < names[i].length; j++) {
System.out.println(names[i][j]);
}
System.out.println();
}
}
}
运算符
Java中的算术运算符、赋值运算符如下所示:
比较运算符、逻辑运算符如下:
各运算符优先级如下
if语句、switch语句、while、do while、for和foreach循环
函数方法
类函数不可直接使用,而是通过创建对象来调用
public class HelloWorld {
public static void main(String[] args) {
// 创建对象,对象名为hello
HelloWorld hello=new HelloWorld();
// 调用方法
hello.show();
}
/*
* 定义无参无返回值的方法
*/
public void show() {
System.out.println("Hello World!");
}
}
3、面向对象
Java类定义中的变量分为成员变量和局部变量,成员变量定义在类中直接定义并且可供类中的所有方法使用,Java会自动完成其初始化工作。局部变量定义在某个具体函数中,且只可以在该函数中使用,不会被初始化。
注意别static修饰的为静态成员变量/方法,静态方法只能调用静态的成员。
public class ObjectOriented {
private static String str; // 静态成员变量定义
int anInt; // 成员变量定义
public static void main(String[] args) {
System.out.println(str); // 静态方法main只能调用静态成员变量,输出null
ObjectOriented ob=new ObjectOriented();
ob.call(); // 通过对象调用普通方法
}
void call(){
String s2; // 局部变量定义
System.out.println(s2); // 报错,局部变量未初始化
System.out.println(anInt); // 普通方法调用普通成员变量,输出0
}
}
类构造方法和类名相同,没有返回值
public class ObjectOriented {
double aDouble; // 成员变量定义
int anInt;
public static void main(String[] args) {
ObjectOriented ob=new ObjectOriented(2,3.6); // 调用类构造方法
System.out.println(ob.anInt+ob.aDouble); // 访问赋值后的成员变量
}
public ObjectOriented(int i,double d){ // 定义构造方法
System.out.println("构造方法执行");
anInt=i; // 在构造方法中完成对成员变量的赋值
aDouble=d;
}
}
Java可以通过初始化块进行数据赋值,类的声明中,可以包含多个初始化块,当创建类的实例时,就会依次执行这些代码块。如果使用 static 修饰初始化块,就称为静态初始化块。静态初始化块只在类加载时执行,且只会执行一次,同时静态初始化块只能给静态变量赋值,不能初始化普通的成员变量。程序运行时静态初始化块最先被执行,然后执行普通初始化块,最后才执行构造方法。
封装
Java通过封装成员变量方式数据被随意修改和访问,封装首先将数据的类型修改为private禁止外部访问,之后定义setter和getter方法用于设置和访问成员变量,可以在setter/getter中对于赋值和显示的数据进行中间操作。在IDEA编辑器中按下alt+insert弹出自动生成器,选中getter and setter会自动生成成员变量的相应方法。
为了防止类名的冲突,Java引入了包来管理类的命名空间,相同包的类之间可以互相可见,在程序最开头通过package声明包名,如果希望引入包使用import关键字,不同层的包名通过.连接
package com.basic; // 声明包
public class Student {
private int age; // 将成员变量设为私有
public int getAge() { // 设置getter和setter方法
return age;
}
public void setAge(int age) {
this.age = age;
}
}
public class ObjectOriented {
public static void main(String[] args) {
Student s1=new Student();
s1.setmAge(24); // 通过setter方法设置私有成员变量
System.out.println(s1.getmAge()); // 通过getter方法访问私有成员
}
}
Java访问修饰符作用范围
Java在类的内部还可以定义子类,称为内部类,通过内部类可以便捷地访问外部类的所有属性和方法,并且将子类封装到内部使外部不可见。内部类对象的创建需要借助外部类对象来new。外部类无法访问内部类的方法,需要通过内部类的对象来调用。当内部类成员属性名与外部相同时,默认访问内部类的,可以通过外部类名.this.属性名的方式访问到外部类成员属性。
//外部类HelloWorld
public class HelloWorld {
//外部类的私有属性name
private String name = "外部类";
//外部类的成员属性
int age = 20;
//成员内部类Inner
public class Inner {
String name = "内部类";
//内部类中的方法
public void show() {
System.out.println("外部类中的name:" + HelloWorld.this.name);
System.out.println("内部类中的name:" + name);
System.out.println("外部类中的age:" + age);
}
}
//测试成员内部类
public static void main(String[] args) {
//创建外部类的对象
HelloWorld o = new HelloWorld();
//创建内部类的对象
Inner inn = o.new Inner();
//调用内部类对象的show方法
inn.show();
}
}
继承
当子类继承父类后,在新建一个子类对象时需要对所有父类和子类的成员变量进行初始化,其初始化顺序为先初始化父类成员变量,再执行父类构造方法,最后再初始化子类的成员变量、构造方法。例如
//父类定义
public class Parent {
int age=10; // 1、初始化父类成员变量
public Parent() { // 2、执行父类构造方法
System.out.println("父类构造方法,age="+age);
age=20;
System.out.println(age);
}
}
//子类定义
public class Son extends Parent {
int age=30; // 3、初始化子类成员
public Son() { // 4、执行子类构造方法
System.out.println("子类构造方法,age="+age);
this.age = 40;
System.out.println(age);
}
public static void main(String[] args) {
Son s=new Son();
}
}
继承中final和super关键字的使用
Java中所有的类默认继承Object类,object有许多默认的方法供子类继承。
toString()用于将类转化为字符串,默认会输出对象的哈希码(用于唯一标识区分对象的码),我们可以手动重写该方法,返回人工定义的字符串内容。再IDEA中通过alt+insert快捷键弹出自动生成工具,选择toString即可自动生成输出类成员属性的toString()方法。
equals()用于比较两个对象是否相同,默认会比较两个对象是否指向同一个引用。我们可以手动重写该方法,通过比较两个对象的属性值来判断是否相同。同理可以自动生成代码实现equals()。
public class Son extends Parent {
int age=30;
@Override
public String toString() { // 打印Son对象及属性值,输出:Son{age=30}
return "Son{" + "age=" + age + '}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true; // this和o指向同一块引用,则一定相同
if (!(o instanceof Son)) return false; // 如果o不是Son类型,一定不同
Son son = (Son) o; // 否则将o转化为Son类型
return age == son.age; // 比较两个Son类型的属性值是否一样
}
public static void main(String[] args) {
Son s=new Son();
System.out.println(s); // 当需要将对象s转化为字符串时,自动调用toString方法
Son s2=new Son();
// 比较两个Son对象,由于age使用相同默认值,所以结果为true
System.out.println(s.equals(s2));
}
多态
引用多态是指父类对象的引用可以指向子类对象,注意反之不可以。
方法多态是指指向子类的父类引用在调用方法时会优先选择子类重写之后的方法。
public class Parent {
public void show(){
System.out.println("这是父类");
}
public void showParent(){
System.out.println("这是父类独有方法");
}
}
public class Son extends Parent {
public void show(){
System.out.println("这是子类");
}
public void showSon(){
System.out.println("子类独有方法");
}
public static void main(String[] args) {
Parent p=new Son(); // 指向子类的父类引用
p.show(); // 优先选择子类重写后的方法,输出:这是子类
p.showParent(); // 可以调用父类独有的方法
p.showSon(); // 报错,父类引用不可以调用子类独有的方法
}
}
抽象类,在IDEA中定义子类时,将鼠标置于父类名上点击alt+enter自动补全实现父类所定义的抽象方法
public abstract class Parent { // 抽象类
public abstract void func(); // 抽象类中定义抽象方法
}
public class Son extends Parent {
@Override
public void func() { // 子类中实现抽象类所定义的抽象方法
System.out.println("子类实现父类的抽象方法");
}
public static void main(String[] args) {
Son s=new Son();
s.func();
}
}
Java中的接口用于描述类的规范,定义了一些常量和继承它的子类所必须实现的抽象方法。与只能继承一个父类不同,子类可以继承多个接口,继承的父类写在接口之前。也可以通过匿名内部类的方式定义类并实现接口,代码更加简洁快速。
public interface IWalk {
public void walk();
}
public class Son extends Parent implements IWalk{ // 子类继承实现接口
@Override
public void walk() {
System.out.println("实现接口中的walk方法");
}
public static void main(String[] args) {
IWalk w=new Son();
w.walk();
IWalk w2=new IWalk() { // 定义一个匿名内部类实现接口
@Override
public void walk() {
System.out.println("匿名内部类实现接口");
}
};
w2.walk();
}
}
4、异常处理
Java中常见的异常如下所示,其中所有异常的父类为Throwable,它的子类Error为运行环境出现问题,Exception为编写的代码出现错误导致的。
如下所示为异常的抛出、捕获和处理的过程
import java.util.InputMismatchException;
import java.util.Scanner;
public class TryCatch {
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
try { // 测试代码块
System.out.print("请输入被除数:");
int a=input.nextInt();
System.out.print("请输入除数:");
int b=input.nextInt();
if (a<b){ // 抛出自定义异常
throw new Exception("被除数小于除数!");
}
System.out.println("商为:"+a/b);
}catch (InputMismatchException e){
System.out.println("请输入整数!");
}catch (ArithmeticException e){ // 并列捕获多个异常
System.out.println("除数不能为0!");
}catch (Exception e){ // 先子类后父类异常
System.out.println(e.getMessage());
}finally { // 最后要执行的操作
System.out.println("执行结束!");
}
}
}
我们可以自定义异常类,需要继承现有的异常类。当某个方法抛出异常后需要对该异常进行try...catch处理,或者将该异常向上抛出给调用该方法的函数,如果一层一层向上抛出就形成了一个异常链。
// 自定义异常继承自父类Exception
public class MyException extends Exception {
public MyException(String message) {
super(message); // 调用父类构造方法完成含参初始化构造器
}
}
public class ExceptionChain {
public static void main(String[] args) {
ExceptionChain ec=new ExceptionChain();
ec.func2(); // 调用func2会接收到fun1所抛出的异常并显示:抛出的自定义异常
}
public void func1() throws MyException { // func1不处理异常,将其抛出
throw new MyException("抛出的自定义异常");
}
public void func2(){
try{
func1(); // 在调用func1时收到其抛出的异常,并处理该异常
}catch (MyException e){
System.out.println(e.getMessage());
}
}
}