Java 语言源于 1991 年 4 月,Sun 公司 James Gosling博士 领导的绿色计划(Green Project) 开始启动,此计划最初的目标是开发一种能够在各种消费性电子产品(如机顶盒、冰箱、收音机等)上运行的程序架构。这个就是Java的
前身:Oak (得名与Java创始人James Gosling办公室外的一棵橡树),但由于这些智能化家电的市场需求没有预期的高,Sun公司放弃了该项计划。随着1995年代互联网的发展,Sun公司看见Oak在互联网上应用的前景,于是改造了Oak,于1995年5月以Java的名称正式发布,并提出“Write once, Run anywhere"(一次写入,随处运行) 的口号。
示例:
public class HelloWorld{
public static void main(String[] args){
System.out.println("Hello world");
}
}
Java程序的结构由如下三个部分组成:
- 源文件(扩展名为*.java):源文件带有类的定义。类用来表示程序的一个组件,小程序或许只会有一个类。类的内容必须包含在花括号里面。
- 类:类中带有一个或多个方法。方法必须在类的内部声明。
- 方法:在方法的花括号中编写方法应该执行的语句。
总结:类存在于源文件里面;方法存在于类中;语句存在于方法中。
注意:在一个源文件中只能有一个public修饰的类,而且源文件名字必须与public修饰的类名字相同。
先通过javac编译程序把源文件进行编译,编译后生成的.class文件是由字节
码组成的平台无关、面向JVM的文件。最后启动java虚拟机来运行.class文件,此时JVM会将字节码转换成平台能够理解的形式来运行。
我们可以用记事本或 idea(集成开发环境)来编写Java源程序,然后使用javac.exe编译器编译源程序,生成xxx.class的字节码文件,语法格式:
javac xxx.java ,最后用java运行字节码文件,语法格式:Java xxx
注意:在运行Java程序前,必须先安装好JDK(Java Development Kit即Java开发工具包),JDK里面就包含了javac和java工具,Java程序最终是在JVM(Java虚拟机)中运行的。
JDK、JRE、JVM之间的关系:
JDK(Java Development Kit):Java开发工具包,提供给Java程序员使用,包含了JRE,同时还包含了编译
器javac与自带的调试工具Jconsole、jstack等。
JRE(Java Runtime Environment):Java运行时环境,包含了JVM,Java基础类库。是使用Java语言编写程
序运行的所需环境。
JVM:Java虚拟机,运行Java代码
在Java中数据类型主要分为两类:基本数据类型和引用数据类型。
基本数据类型有四类八种:
int 的包装类型为 Integer
long 的包装类型为 Long
short 的包装类型为 Short
byte 的包装类型为 Byte
double 的包装类型为 Double
float 的包装类型为 Float
char 的包装类型为 Character
boolean 的包装类型为 Boolean
总结:除了int 和 char 类型的包装类要特殊记忆外,其它六种基本数据类型所对应的包装类都是首字母大写即可。
引用数据类型有:数组、类、接口、抽象类、自定义类型等
加减乘除模(+ - * / %)
都是二元运算符,使用时必须要有左右两个操作数
int / int 结果还是int类型,而且会向下取整
做除法和取模时,右操作数不能为0
% 不仅可以对整型取模,也可以对double类型取模,但是没有意义,一般都是对整型取模的
两侧操作数类型不一致时,向类型大的提升
增量运算符 += -= *= %=
该种类型运算符操作完成后,会将操纵的结果赋值给左操作数。
int a = 1; a += 2; // 相当于 a = a + 2
注意:只有变量才能使用该运算符,常量不能使用。
自增/自减运算符 ++ –
+是给变量的值+1,–是给变量的值-1。
注意:
如果单独使用,【前置++】和【后置++】没有任何区别
如果混合使用,【前置++】先+1,然后使用变量+1之后的值,【后置++】先使用变量原来的值,表达式
结束时给变量+1
只有变量才能使用自增/自减运算符,常量不能使用,因为常量不允许被修改
关系运算符主要有六个: == != < > <= >= ,其计算结果是 true 或者 false 。 逻辑运算符主要有三个: && || ! ,运算结果都是 boolean类型。比较简单简略带过。 移位运算符有三个: << >> >>> ,都是二元运算符,且都是按照二进制比特位来运算的。 1、 左移 <<: 最左侧位不要了, 最右侧补 0. 这里我们学习了if、if…else、switch语句,还有for、while、do…while循环等。 switch的括号内只能是以下类型的表达式: java中把函数叫做方法,它是完成某个功能,模块化的组织代码。 着重强调方法的重载、重写,以及这两者的区别。 重载特点: 重写特点: 一个方法在执行过程中调用自身, 就称为 “递归”。 递归的必要条件: 递归的程序的执行过程不太容易理解, 要想理解清楚递归, 必须先理解清楚 “方法的执行过程”, 尤其是 “方法执行结束之后, 回到调用位置继续往下执行”. 定义:可以看成是相同类型元素的一个集合。在内存中是一段连续的空间。 注意:数组可以作为参数和返回值: 操作数组的工具类:Arrays 二维数组本质上也就是一维数组, 只不过每个元素又是一个一维数组。 例如: 输出: 什么是类? 成员变量定义在方法的外部,类的内部。 普通成员变量: 普通成员方法:属于对象的,对象的引用与点号的结合进行访问。 通过描述,产生一个真正的实体对象,主要通过new关键字来实例化对象。 this是当前对象的引用,三种用法: 方法名与类名一样,没有返回值。 作用:实例化对象的时候调用,同时可以初始化我们的成员变量。 我们有两种初始化: 当我们没有添加任何构造方法时,编译器会帮我们提供一个不带参数的构造方法,而当我们添加了构造方法时,编译器就不会再提供构造方法了。 注意:构造方法可以重载。 含义:指将内部的实现细节进行了隐藏,不要让类外直接获取到我不想让它获取到的东西。从代码层面来讲,就是使用关键字private进行修饰。 我们可以使用get和set方法来对封装的数据进行访问。 普通代码块:定义在方法中的代码块。 new对象时,静态代码块和非静态代码块与构造方法的执行顺序:先是静态的执行(只执行一次,下次就不执行了),然后是非静态的,最后是构造方法执行。 即在类里再定义一个类。 注意: 被static修饰的内部成员类称为静态内部类。 注意: 总结:如果设计的内部类依赖于外部类对象,那就设计成非静态的内部类,反之就设计成静态内部类。 还有一个匿名内部类,就是没有名字的内部类,多用于接口的实现。 为什么要继承呢? 该关键字主要作用:在子类方法中访问父类的成员。 super 的几种用法: super和this都可以在成员方法中访问:成员变量和调用其他的成员函数,都可以作为构造方法的第一条语句,那它们之间有什么区别呢? 同: 异: 1、父类静态代码块优先于子类静态代码块执行,且是最早执行 final关键可以用来修饰变量、成员方法以及类。 注意三个点: 啥是多态? 父类类型引用子类对象, 这便是向上转型. 缺点 : 只能通过父类引用 访问父类自己的成员. 什么时候发生向上转型呢? 第一种就是直接赋值了 : 还有就是方法的传参 , 就是将子类对象传入父类类型参数里 : 再就是方法的返回值了 : 关于动态绑定 : 通过父类引用 , 调用子类重写了的父类的方法. 抽象类也是类,内部可以包含普通方法和属性,甚至构造方法 抽象类本身不能被实例化, 要想使用, 只能创建该抽象类的子类, 然后让子类重写抽象类中的抽象方法,使用抽象类相当于多了一重编译器的校验。 接口不能直接使用,必须要有一个"实现类"来"实现"该接口,实现接口中的所有抽象方法。 类和类之间是单继承的,一个类可以实现多个接口,接口与接口之间可以多继承。即:用接口可以达到多继承的目的。 注意 : 核心区别: 1.比较是否引用同一个对象 对于内置类型,== 比较的是变量中的值;对于引用类型,比较的是引用中的地址。 String类重写了父类Object中equals方法,Object中equals默认按照==比较,String重写equals方法后,按照如下规则进行比较,比如: s1.equals(s2) 与equals不同的是,equals返回的是boolean类型,而compareTo返回的是int类型。具体比较方式: 由于String的不可更改特性,为了方便字符串的修改,Java中又提供StringBuilder和StringBuffer类。这两个类大部分功能是相同的. String和StringBuilder最大的区别在于String的内容无法修改,而StringBuilder的内容可以修改。频繁修改字符串的情况考虑使用StringBuilder. 注意:String和StringBuilder类不能直接转换。如果要想互相转换,可以采用如下原则: String、StringBuffer、StringBuilder的区别: String的内容不可修改,StringBuffer与StringBuilder的内容可以修改. 异常种类繁多,为了对不同异常或者错误进行很好的分类管理,Java内部维护了一个异常的体系结构: 借助throw关键字,抛出一个指定的异常对象,将错误信息告知给调用者。 注意: 主要有两种:异常声明throws 以及 try-catch捕获处理。 处在方法声明时参数列表之后,当方法中抛出编译时异常,用户不想处理该异常,此时就可以借助throws将异常抛给方法的调用者来处理。即当前方法不处理异常,提醒方法的调用者处理异常。 注意: throws对异常并没有真正处理,而是将异常报告给抛出异常方法的调用者,由调用者处理。如果真正要对异常进行处理,就需要try-catch. 注: 注意: 在catch 语句里我们有三种处理异常方法: finally中的代码一定会执行的,一般在finally中进行一些资源清理的扫尾工作。 Java 中虽然已经内置了丰富的异常类, 但是并不能完全表示实际开发中所遇到的一些异常,此时就需要维护符合我们实际情况的异常结构。 实现方式: 注意: 举个例子,实现一个用户登录功能:
注意:当需要多次判断时,不能连着写,比如:3 < a < 5,应该写成:3
逻辑运算符
移位运算
注意:向左移位时,丢弃的是符号位,因此正数左移可能会编程负数
2、 右移 >>: 最右侧位不要了, 最左侧补符号位(正数补0, 负数补1)
3、 无符号右移 >>>: 最右侧位不要了, 最左侧补 0逻辑控制
我们要注意:主要是判断条件,就一定是布尔表达式。
还要注意switch的参数的数据类型有哪些。
基本类型:byte、char、short、int,注意不能是long类型
引用类型:String常量串、枚举类型方法
方法的重载与重写
方法名相同,参数列表不同(顺序、数据类型、个数),返回值不做要求。
注意:子类也可以重载父类的方法。
方法名相同,参数列表相同(顺序、数据类型、个数),返回值相同(除非可以构成父子类关系)。
注意:
private 修饰的方法不能重写
static 修饰的方法不能重写
被final修饰的方法不能重写
子类重写方法后,访问权限要大于等于父类的访问权限。关于递归
数组
数组在java中是引用类型。二维数组
数据类型[][] 数组名称 = new 数据类型 [行数][列数] { 初始化数据 };
public static void main(String[] args) {
int[][] arr = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12}
}; //二维数组的每一行,相当于一维数组的每个元素
for(int row = 0; row < arr.length; row++) {
for (int col = 0; col < arr[row].length; col++) {
System.out.printf("%d\t", arr[row][col]);
}
System.out.println("");
}
}
1 2 3 4
5 6 7 8
9 10 11 12
二维数组就类似于一个特殊的一维数组,每个元素相当于一个一维数组,每个一维数组的大小可以不同。
类和对象
类就是描述某个对象的一些属性和行为。成员变量
属于对象的,对象的引用与点号的结合进行访问,所占用的内存是在对象中的。
静态成员变量:
加static关键字,表面当前成员变量是属于类的变量。类变量是存放在方法区的。成员方法
静态成员方法:不依赖于对象,直接可以通过类名点出来。
注意:不能在静态方法中使用非静态成员变量。(因为非静态成员变量依赖于对象)对象
一个类可以实例化多个对象。this 关键字
1.引用当前对象的变量:this.data
2.引用当前对象的方法:this.fun()
3.引用当前对象的构造方法:this()构造方法
就地初始化:创建变量时赋值。
默认初始化:创建变量时不赋值。(变量是默认值,不同数据类型默认值是不同的)封装
代码块
构造代码块:定义在类中的代码块(加修饰符)。也叫:实例代码块。构造代码块一般用于初始化实例成员变量。
静态代码块:使用static定义的代码块称为静态代码块。一般用于初始化静态成员变量。内部类
非静态内部类
public class OutClass {
private int a;
static int b;
int c;
public void methodA() {
a = 10;
System.out.println(a);
}
public static void methodB() {
System.out.println(b);
}
// 实例内部类:未被static修饰
class InnerClass {
int c;
public void methodInner() {
// 在实例内部类中可以直接访问外部类中:任意访问限定符修饰的成员
a = 100;
b = 200;
methodA();
methodB();
// 如果外部类和实例内部类中具有相同名称成员时,优先访问的是内部类自己的
c = 300;
System.out.println(c);
// 如果要访问外部类同名成员时候,必须:外部类名称.this.同名成员名字
OutClass.this.c = 400;
System.out.println(OutClass.this.c);
}
}
public static void main(String[] args) {
// 外部类:对象创建 以及 成员访问
OutClass outClass = new OutClass();
System.out.println(outClass.a);
System.out.println(OutClass.b);
System.out.println(outClass.c);
outClass.methodA();
outClass.methodB();
System.out.println("=============实例内部类的访问=============");
// 要访问实例内部类中成员,必须要创建实例内部类的对象
// 而普通内部类定义与外部类成员定义位置相同,因此创建实例内部类对象时必须借助外部类
// 创建实例内部类对象
OutClass.InnerClass innerClass1 = new OutClass().new InnerClass();
// 上述语法比较怪异,也可以先将外部类对象先创建出来,然后再创建实例内部类对象
OutClass.InnerClass innerClass2 = outClass.new InnerClass();
innerClass2.methodInner();
}
}
静态内部类
public class OutClass {
private int a;
static int b;
public void methodA(){
a = 10;
System.out.println(a);
}
public static void methodB(){
System.out.println(b);
}
// 静态内部类:被static修饰的成员内部类
static class InnerClass{
public void methodInner(){
// 在内部类中只能访问外部类的静态成员
// a = 100; // 编译失败,因为a不是静态变量
b =200;
// methodA(); // 编译失败,因为methodB()不是静态成员方法
methodB();
}
}
public static void main(String[] args) {
// 静态内部类对象创建 & 成员访问
OutClass.InnerClass innerClass = new OutClass.InnerClass();
innerClass.methodInner();
}
}
继承和多态
继承
class A extends B {
}
继承是共性的抽取,从而达到对代码的复用。
子类继承父类的所有成员变量和方法(非静态的)。super 关键字
访问父类的成员变量:super.data
访问父类的方法:super.func()
调用父类的构造方法:super()super 与 this 的区别
代码块执行顺序
class Person {
public String name;
public int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
System.out.println("Person:构造方法执行");
}
{
System.out.println("Person:实例代码块执行");
}
static {
System.out.println("Person:静态代码块执行");
}
}
class Student extends Person{
public Student(String name,int age) {
super(name,age);
System.out.println("Student:构造方法执行");
}
{
System.out.println("Student:实例代码块执行");
}
static {
System.out.println("Student:静态代码块执行");
}
}
public class TestDemo4 {
public static void main(String[] args) {
Student student1 = new Student("张三", 15);
System.out.println("===========================");
Student student2 = new Student("李四", 35);
}
}
2、父类实例代码块和父类构造方法紧接着执行
3、子类的实例代码块和子类构造方法紧接着再执行
4、第二次实例化子类对象时,父类和子类的静态代码块都将不会再执行访问修饰限定符
final 关键字
多态
就是一个引用,引用的对象不一样, 所表现的行为不一样, 这种思想被称为多态.向上转型
class Animal {
}
class Cat extends Animal {
}
Animal animal = new Cat();
Animal animal = new Cat();
public static void fun(Animal animal) { //这里传入Cat类型参数,就是向上转型了
}
public static Animal fun(Animal animal) {
return new Cat();
}
抽象类和接口
抽象类
抽象类语法
// 抽象类:被abstract修饰的类
public abstract class A {
// 抽象方法:被abstract修饰的方法,没有方法体
abstract public void fun();
abstract void func();
// 抽象类也是类,也可以增加普通方法和属性
public double funcc(){
return m;
}
protected double f;
}
抽象类特性
抽象类作用
接口
接口语法
public interface 接口名称,接口名称...{ //可以实现多个接口
// 抽象方法
public abstract void method1(); // public abstract 是固定搭配,可以不写
public void method2();
abstract void method3();
void method4();
// 注意:在接口中上述写法都是抽象方法,少写固定搭配让代码更简洁
}
接口使用
注意:子类和父类之间是extends 继承关系,类与接口之间是 implements 实现关系。接口间的继承
接口可以继承一个接口, 达到复用的效果. 使用 extends 关键字。
接口间的继承相当于把多个接口合并在一起,不需要去实现接口中的方法。接口特性
一个类可以实现多个接口 (继承是只能继承一个)
一个类实现多个接口时,每个接口中的抽象方法都要实现,否则类必须设置为抽象类。( IDEA 中使用 ctrl + i 快速实现接口)抽象类和接口的区别
抽象类中可以包含普通方法和普通字段, 这样的普通方法和字段可以被子类直接使用(不必重写), 而接口中不能包含普通方法, 子类必须重写所有的抽象方法.String
字符串构造的常用三种方法
public static void main(String[] args) {
// 使用常量串构造
String s1 = "hello world";
System.out.println(s1);
// 直接newString对象
String s2 = new String("hello world");
System.out.println(s1);
// 使用字符数组进行构造
char[] array = {'h','e','l','l','o','w','o','r','l','d'};
String s3 = new String(array);
System.out.println(s1);
}
String对象的比较
public boolean equals(Object anObject) {
// 1. 先检测this 和 anObject 是否为同一个对象比较,如果是返回true
if (this == anObject) {
return true;
}
// 2. 检测anObject是否为String类型的对象,如果是继续比较,否则返回false
if (anObject instanceof String) {
// 将anObject向下转型为String类型对象
String anotherString = (String)anObject;
int n = value.length;
// 3. this和anObject两个字符串的长度是否相同,是继续比较,否则返回false
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
// 4. 按照字典序,从前往后逐个字符进行比较
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
public static void main(String[] args) {
String s1 = new String("abc");
String s2 = new String("ac");
String s3 = new String("abc");
String s4 = new String("abcdef");
System.out.println(s1.compareTo(s2)); // 不同输出字符差值-1
System.out.println(s1.compareTo(s3)); // 相同输出 0
System.out.println(s1.compareTo(s4)); // 前k个字符完全相同,输出长度差值 -3
}
public static void main(String[] args) {
String s1 = new String("abc");
String s2 = new String("ac");
String s3 = new String("ABc");
String s4 = new String("abcdef");
System.out.println(s1.compareToIgnoreCase(s2)); // 不同输出字符差值-1
System.out.println(s1.compareToIgnoreCase(s3)); // 相同输出 0
System.out.println(s1.compareToIgnoreCase(s4)); // 前k个字符完全相同,输出长度差值 -3
}
StringBuilder和StringBuffer
String变为StringBuilder: 利用StringBuilder的构造方法或append()方法
StringBuilder变为String: 调用toString()方法
StringBuffer与StringBuilder大部分功能是相似的
StringBuffer采用同步处理,属于线程安全操作;而StringBuilder未采用同步处理,属于线程不安全操作异常
异常的体系结构
StackOverflowError和OutOfMemoryError,一旦发生回力乏术。异常分类
在程序编译期间发生的异常,称为编译时异常,也称为受查异常
在程序执行期间发生的异常,称为运行时异常,也称为非受查异常
RunTimeException以及其子类对应的异常,都称为运行时异常。比如:NullPointerException、ArrayIndexOutOfBoundsException、ArithmeticException。异常抛出
throw new XXXException("异常产生的原因");
异常的捕获
异常声明throws
修饰符 返回值类型 方法名(参数列表) throws 异常类型1,异常类型2...{
} //可以声明多个异常
try-catch捕获并处理
try{
// 将可能出现异常的代码放在这里
}catch(要捕获的异常类型 e){
// 如果try中的代码抛出异常了,此处catch捕获时异常类型与try中抛出的异常类型一致时,或者是try中抛出异常的基类时,就会被捕获到
// 对异常就可以正常处理,处理完成后,跳出try-catch结构,继续执行后序代码
}[catch(异常类型 e){
// 对异常进行处理
}finally{
// 此处代码一定会被执行到
}]
// 后序代码
// 当异常被捕获到时,异常就被处理了,这里的后序代码一定会执行
// 如果捕获了,由于捕获时类型不对,那就没有捕获到,这里的代码就不会被执行
只打印异常信息:System.out.println(e.getMessage());
打印异常类型,异常信息:System.out.println(e);
打印信息最全面:e.printStackTrace();finally
try{
// 可能会发生异常的代码
}catch(异常类型 e){
// 对捕获到的异常进行处理
}finally{
// 此处的语句无论是否发生异常,都会被执行到
}
// 如果没有抛出异常,或者异常被捕获处理了,这里的代码也会执行
自定义异常
自定义异常通常会继承自 Exception 或者 RuntimeException
继承自 Exception 的异常默认是受查异常
继承自 RuntimeException 的异常默认是非受查异常public class Test {
public static void fun(String name2, String code2) throws PasswordException, UsernameException {
String name = "张三";
String code = "666666";
if(!name2.equals(name)) { //如果输入的姓名或密码错误,则抛出异常
throw new PasswordException("用户名错误!");
}
if(!code2.equals(code)) {
throw new UsernameException("密码错误!");
}
System.out.println("输入成功!!!");
}
public static void main(String[] args) throws PasswordException, UsernameException {
Scanner scanner = new Scanner(System.in);
String name = scanner.nextLine();
String code = scanner.nextLine();
fun(name,code);
}
}
public class PasswordException extends Exception{
public PasswordException(String message) {
super(message);
}
}
public class UsernameException extends Exception{
public UsernameException(String message) {
super(message);
}
}