第一章 Java简介
1.1 Java介绍
(1)Java语言足够简单。
(2)Java是一门面对对象的编程语言
(3)Java是为数不多的多线程编程语言
(4)Java提供了自动的垃圾回收机制,以更好的处理垃圾空间
(5)Java避免了复杂的指针问题,而使用了使用了更加简单的引用处理来完成内存空间的匹配问题
(6)Java可以实现任意平台的移植
1.2 JDK的安装与配置
JRE包括Java虚拟机、Java核心类库和支持文件,JDK包含开发工具和编译器
1.3 第一个Java程序
Java程序分为两个操作
1.编译程序:javac Hello.java,此时会形成Hello.class文件,这就属于字节码文件
2.解释程序:java Hello
所有Java程序都有一个最为核心的单元:类
public class 类名称{}:文件名称必须与类名称保持一致,一个java文件只能有一个public class
class 类名称{}:文件名称可以与类名称不一致,但是生成的.class文件和类名一致,java文件里面可以有多个class,但是编译后会生成多个不同的.class文件
1.4 CLASSPATH环境属性
PATH:是属于操作系统路径,定义所有可执行程序的路径
CLASSPATH:是Java程序解释类文件时所使用的加载路径
CLASSPATH主要目的是定义类的加载路径
安装一些程序可能去修改已经设置好的CLASSPATH,可能导致你的程序无法正确执行,所以要进行手工修改
第二章 程序基本概念
2.1 Java注释
// 单行注释
/* … / 多行注释
/* … */ 文档注释
尽可能使用单行注释,原因:在一些开发工具里面,多行注释格式化后的效果不好
2.2 标识符与关键字
2.3 数据类型划分
基本数据类型不牵扯到内存分配问题,而引用数据类型
基本数据类型
数值型
整型:byte short int long
浮点性:float double
字符型:char
布尔型:boolean
引用数据类型:数组、类、接口
2.4 运算符
2.5 程序逻辑控制
2.6 方法的定义及使用
方法重载的时候重点是根据参数类型以及个数来区分方法
##第三章
###String类操作方法
//字符与字符串
public String(char[] value)
public String(cahr[], int offset, int count)
public char charAt(int index)
public char[] toCharArray()
//字节与字符串
public String(byte[] bytes)
public String(byte[] bytes, int offset, int length)
public byte[] getBytes()
//字符串比较
public boolean equals(String anObject)
public boolean equalsIgnoreCase(String anObject)
public booean int compareTo(String anObject)
//字符串查找
public boolean contains(String s)
public int indexOf(String str)
public int lastIndex(String str)
public boolean startWith(String prefix)
public boolean endWith(String suffix)
//字符串替换
public String replaceAll(String regex, String replacement)
public String replaceFirst(String regex, String replacement)
//字符串截取、拆分
public String substring(int begIndex)
public String[] split(String regex)
//其他方法
public String concat(String str)
public String toLowerCase()
public String toUpperCase()
public String toUpperCase()
public String trim()
public int length()
public String intern()
public boolean isEmpty()
this关键字
this调用构造方法的时候一定要放在代码的首行且一定要留有调用的出口
static关键字
在java
中主要存在4块内存空间
- 栈内存空间
- 堆内存空间
- 全局数据区
- 全局代码区
- static定义在类中作为公共属性,由
类名.变量
调用 - static方法不能直接访问static属性和方法,只能调用static属性和方法
- 非static方法没有限制
说明
- 所有非static定义的结构,必须在类已经明确产生实例化对象时才会分配内存空间,才可以使用
- 所有static定义的结构,不受实例化对象的控制,可以在没有实例化对象的情况下调用
###代码块
- 普通代码块
- 构造块 使用在类中可以限于构造函数执行
- 静态块 静态块在加载类的时候运行且只运行一次
###内部类
- 可以轻松访问外部类的私有属性
- 将内部类定义为私有的话此内部类只服务于次内部类的外部类
- static定义内部类会成为一个"外部类",并且只能调用外部类的static属性和方法
##第四章 面对对象高级知识
###继承
- 能单继承,但可以多重继承
- 私有操作属于隐式继承,其他属于显式继承(父类的私有属性还是只能在父类的方法中去访问)
- 构造方法的调用顺序是先调用父类再调用子类,注意在子类构造函数中有一个隐式的super()调用,我们可以显式调用它
###覆写
-
子类覆写父类的方法,函数名、返回值、参数类型、参数个数要一模一样(这一点是区别与重载的)
-
关于覆写方法的执行问题
- 观察实例化对象是哪个类
- 调用的方法有没有在子类中被覆写
-
被子类覆写的方法不能比父类有更严格的访问权限(但是可以父类中的私有方法,在子类中是以public形式出现的,此时子类中的方法和父类的方法是两个完全不一样的东西)
this和super的区别:super只会在父类中寻找对应的属性和方法,this会优先找本类的属性和方法,找不到再去父类找
final关键字
- final定义的类不能被继承,定义的方法不能被子类覆写
- final可以定义常量,publc static final 可以定义全局常量(常量的书写规则是全部大写)
多态性
多态性分为方法的多态和父子类对象的转换
- 对象的向上转型
A a = new B(); a.print();
目的是参数的统一,子类实例化后的父类只能调用父类中定义过的方法 - 对象的向下转型
A a = new B(); B b = (B)a; b.print()
父类可以调用子类中定义过单父类中没有定义过的方法,也就是子类特有的方法,但会带来一定的操作隐患
为了保证转型顺利通常使用instanceof判断一个对象是否是某个类的实例化对象
a instanceof A
a instanceof B
###抽象类
- 抽象类不可以直接实例化对象
- 抽象类必须以abstract定义类,抽象类中可以存在抽象方法也用abstract定义
- 抽象类必须有子类
- 抽象类中的抽象方法强制子类覆写
- 可以通过子类来完成抽象类的对象实例化操作
- 可以在抽象类中的普通方法调用抽象方法,具体根据实例化对象的子类进行相应操作
抽象类和接口的区别
- 接口中只能定义常量和抽象方法(并且内部默认常量final,方法abstract),抽象类和普通类一样
- 接口可以多重继承其他接口,抽象类可以实现多重接口
Object
Object类是所有类的父类
- toString()输出一个对象信息的方法,默认自动调用
- equals()
- hashCode()
理论上任何的简单Java类都应该覆写以上的三种方法
基本数据类型的包装类
装箱与拆箱操作
public class TestDemo {
public static void main(String args[]) {
Integer obj = new Integer(10);
int tmp = obj.intValue();
System.out.println(tmp);
System.out.println(obj);
}
}
自动装箱
public class TestDemo {
public static void main(String args[]) {
Integer obj = 10;
int tmp = obj.intValue();
System.out.println(tmp);
System.out.println(obj);
}
}
包装类默认值null
所以Object类可以引用任何数据类型
##第五章 包及访问控制权限
包的一些操作
包实际上指的就是文件夹
javac -d . Hello.java
package com.yootk.util
导入包的路径
import com.yootk.util.Message
导入包中的指定类,也可以使用*导入所有类 (不存在导入的性能上的问题)
public class 和 class的区别
- public class:文件名称必须与类名称保持一致,在一个*.java文件里面只有一个public class声明,如果一个类需要被不同的包访问,那么一定要定义为public class
- class:文件名称可以与类名称不一致,并且一个*.java文件里面可以有多个*.class文件,表明这个类只能被本包的类所访问
jar命令
学习参考
主要是用来打包*.class文件的
访问控制权限
简单理解为private只能在一个类中访问,defalut只能在一个包中访问,protected在不同包的子类中访问,public为所有的都可以
单例模式和多例模式
构造方法私有,在类中使用private static classname = new classname()初始化一个对象,多例模式无非是在单例模式中多增加几个private static 对象,然后类中的方法都是static方法
第六章 异常的捕获及处理
异常捕获处理流程
try {
// 可能出现异常的代码段
} catch (异常类 对象名){
// 异常的处理
} finally {
// 最后都会执行这个
}
异常处理的格式:try…catch…finally、try…catch、try…finally
所有的异常类都会提供printStackTrace()方法,用来输出异常信息
java.lang.Object
|- java.lang.Throwable
|- java.lang.Exception
|- java.lang.RuntimeException
|- java.lang.ArithmeticException
throws关键字
throws关键字主要在方法定义上使用,表示此方法不进行异常处理,而是交给被调用处处理
class Math {
public static int div(int x, int y) throws Exception {
return x / y;
}
}
public class TestDemo {
public static void main(String args[]) {
try {
System.out.println("Math.div(10, 2)");
} catch (Exception e) {
e.printStackTrace();
}
}
}
强行抛出异常:考虑代码的统一性,所以不管调用方法时是否产生异常,都必须进行异常处理的操作
throw关键字
之前所有的异常类对象都是由JVM自动进行实例化操作的,而用户实际上可以自己抛出一个实例化对象的
try {
throw new Exception("123");
} catch (Exception e) {
e.printStackTrace();
}
- main方法处理该异常,使用try…catch语句,将可能会出现的异常的代码放在try块内,将处理异常的代码放在catch块内,并指明catch能够捕获的异常的类型,当异常被捕获时,执行catch块内的语句。
- main方法不处理该异常,将异常向外层程序抛出。在方法声明中使用throws关键字抛出异常,方法体中不需要使用try…catch语句。
RutimeException类
最大的特征:程序在编译时不会强制性要求用户处理异常,但是如果没有处理异常又发生了异常那么就会交给JVM进行默认处理
RuntimeException和Exception的区别
- RuntimeException是Exception的子类
- Exception定义了必须处理的异常,RutimeException定义的异常可以选择性的进行处理
- Exception:在程序中必须使用try…catch进行处理。
- RuntimeException:可以不使用try…catch进行处理,但是如果有异常产生,则异常将由JVM进行处理。
assert关键字
其主要功能是进行一个断言
public static void main(String args[]) {
int num = 10;
assert num == 20 : "num的内容不是20";
System.out.println("num = " + num);
}
java默认是不开启断言的,javac的时候加上-ea参数才会开启断言
第七章 Eclipse开发工具
第八章 Java新特性
可变参数和foreach循环
public void function(int ... num)
可以直接传多个参数,甚至可以传数组
for (数据类型 变量 : 数组 | 集合)
内容依次取出,可以避免索引问题
静态导入
import static 包.类.*
就类似于在主类中定义static方法一样
泛型
泛型能解决的问题
class Point {
private Object x;
private Object y;
public void setX(Object x) {
this.x = x;
}
public void setY(Object y) {
this.y = y;
}
public Object getX() {
return this.x;
}
public Object getY() {
return this.y;
}
public String toString() {
return "Object x = " + this.x + " Object y = " + this.y;
}
}
public class TestDemo {
public static void main(String args[]) {
Point p = new Point();
p.setX("123");
p.setY(10);
String x = (String)p.getX();
String y = (String)p.getY();
System.out.println(p);
}
}
泛型的引入主要是为了解决对象向下转型并不是安全的问题
class Point<T> {
private T x;
private T y;
public void setX(T x) {
this.x = x;
}
public void setY(T y) {
this.y = y;
}
public T getX() {
return this.x;
}
public T getY() {
return this.y;
}
public String toString() {
return "Object x = " + this.x + " Object y = " + this.y;
}
}
public class TestDemo {
public static void main(String args[]) {
Point<String> p = new Point<String>();
p.setX("123");
p.setY(12);
String x = p.getX();
String y = p.getY();
System.out.println(p);
}
}
像这种情况编译期间就会检查出错误,使用泛型后类中的属性都是动态设置的,从而解决了对象转换的安全隐患
如果不设置泛型类型的话会默认使用Object对象
通配符的问题
比如一个泛型类定义了多个不同数据类型的泛型对象,在进行方法调用的时候为了统一参数我们可以使用通配符
public static void fun(Message<?> tmp) {
System.out.println(tmp);
}
// 这样无论你传Message<Integer>、Message<String>都可以进行操作
通配符的上下限
- “? extends 类”:设置泛型上限,可以在声明和方法参数上使用
- ? extends Number:意味着可以设置Number或Number的子类
- “? super 类”:设置泛型的下限,方法参数上使用
- ? super String:意味着只能设置String或它的父类
泛型接口
两种实现方式
- 子类继续设置泛型标记
interface IMessage<T> {
public void print(T t);
}
class MessageImpl<S> implements IMessage<S> {
public void print(S s) {
System.out.println(s);
}
}
- 在子类不设置泛型,而为父类接口明确定义一个泛型
interface IMessage<T> {
public void print(T t);
}
class MessageImpl implements IMessage<String> {
public void print(String s) {
System.out.println(s);
}
}
泛型方法
public static<T> T fun(T t) {
return t;
}
枚举
enum Color {
RED, GREEN, BLUE;
}
public class TestDemo {
public static void main(String args[]) {
Color tmp = Color.RED;
System.out.println(tmp);
}
}
class Color {
private String title;
private static final Color RED = new Color("RED");
private static final Color GREED = new Color("GREED");
private static final Color BLUE = new Color("BLUE");
private Color(String title) {
this.title = title;
}
public static Color getInstance(int ch) {
swich(ch) {
case 1:
return RED;
case 2:
return GREED;
case 3:
return BLUE;
default:
return null;
}
}
public String toString() {
return this.title;
}
}
public class TestDemo {
public static void main(String args[]) {
}
}
可见枚举的作用其实就是简化多例设计模式
Enum类的定义方法
public abstract class Enum <E extends Enum<E>> extends Object implements Comparable<E>, Serializable
- protected Enum(String name, int ordinal)
- public final int ordinal()
- public final String name()
for (Color c : Color.values())
Annotation
@Override 方法覆写
@Deprecated 方法过期 使用会有警告
@SuppressWarnings 压制警告信息
接口定义加强
接口是解决多继承的主要手段
JDK1.8之前只能定义全局常量和抽象方法,现在可以定义default方法和static方法
Lambda表达式
JDK1.8之后引入的特性,指的是应用在单一抽象方法(Single Abstract Method, SAM)接口环境下的一种简化定义形式,可以用于解决匿名内部类的定义复杂问题
匿名内部类和Lambda表达式的比较
//匿名内部类
interface IMessage {
public void print();
}
public class TestDemo {
public static void main(String args[]) {
fun(new IMessage() {
@Override
public void print() {
System.out.println("l love ChenChen");
}
});
}
public static void fun(IMessage msg) {
msg.print();
}
}
//Lambda表达式
interface IMessage {
public void print();
}
public class TestDemo {
public static void main(String args[]) {
fun(() -> System.out.println("l love ChenChen"));
}
public static void fun(IMessage msg) {
msg.print();
}
}
(参数) -> 方法体
基本格式就是这样的
关于@Functionallnterface注解说明
Lambda已经明确是所在接口上进行的一种操作了,并且在接口中只允许定义一个抽象方法,而为了区分Lambda表达式的使用接口,可以在接口上使用"@Functionallterface"注解声明,这样就表示此为函数式接口,里面只允许定义一个抽象方法
方法引用
除了对对象的引用操作,JDK1.8开始也支持在方法上进行引用
Java 8一共定义了四种操作形式
- 引用静态方法:类名称 :: static方法名称
- 引用某个对象的方法:实例化对象 :: 普通方法
- 引用特定类型的方法:特定类 :: 普通方法
- 引用构造方法:类名称 :: new
内建函数式接口
在方法引用过程中不管如何进行操作,对于可能出现的函数式接口的方法也最多只有4类:有参数有返回值、有参数无返回值、无参数有返回值、判断真假
第九章 多线程
多线程实现
如果想要实现多线程,以前要么继承Thread类要么实现Runnable接口,JDK1.5之后引入了新的Callable接口
java.lang.Thread,任何类只需要继承Thread类就可以成为一个线程的主类,线程启动就必须覆写Thread类中的run()方法,并且多线程启动的唯一方法就是Thread类中的start()方法
Thread类部分方法
public synchronized void start() {
if (threadStatus != 0) {
throw new IllegalThreadStateException();
}
group.add(this);
boolean started = false;
try {
start0();
started = true;
} finally {
try {
if (!started) {
group.threadStartFailed(this);
}
} catch (Throwable ignore) {
}
}
}
private native void start0();
Lambda表达式
@FunctionalInterface
public interface Runnable {
public void run();
}
public class TestDemo {
public static void main(String args[]) {
String name = "thread target";
new Thread(() -> {
for (int i = 0; i < 200; ++i) {
System.out.println(name + "-->" + i);
}
})
}
}
两种方式实现多线程
class MyThread1 extends Thread {
@Override
public void run() {
for (int i = 0; i < 10; ++i) {
System.out.println(i + " l love ChenChen");
}
}
}
class MyThread2 implements Runnable {
@Override
public void run() {
for (int i = 0; i < 10; ++i) {
System.out.println(i + " l like ChenChen");
}
}
}
public class TestDemo {
public static void main(String args[]) {
MyThread1 a = new MyThread1();
MyThread2 b = new MyThread2();
a.start();
// a.start();
// new Thread(a).start();
new Thread(b).start();
}
}
Callable接口实现多线程的缘由
Runnable接口实现多线程可以避免单继承的局限,但是它的run()方法不能返回操作结果,所以为了解决这样的问题在JDK1.5引入了一个新的接口,java.util.concurrent.Callable
@FunctionlaInterface
public interface Callable<V> {
public V call() throw Exception;
}
返回的类型由Callable接口上的泛型动态决定 ,写完多线程主体类之后,要利用Thread类启动多线程,但是Thread类中并没有定义任何构造方法可以直接接收Callable接口对象实例,并且由于需要接收call()返回值的问题,从JDK1.5开始,Java提供了一个java.util.concurrent.FutureTask< V >类,定义如下
public class FutureTask<V> extends Object implements RunnableFuture<V>
而RunnableFuture接口又同时实现了Future和Runnable接口
// FutureTask -> RunnableFuture -> Runnble
// -> Future
class MyThread implements Callable<String> {
private int tickets = 10;
@Override
public String call() throws Exception {
for (int i = 0; i < 100; ++i) {
if (this.tickets > 0) {
System.out.println("sall a ticket" + this.tickets--);
}
}
return "over";
}
}
public class TestDemo {
public static void main(String args[]) throws Exception {
MyThread x = new MyThread();
MyThread y = new MyThread();
FutureTask<String> task1 = new FutureTask<String>(x);
FutureTask<String> task2 = new FutureTask<String>(y);
new Thread(task1).start();
new Thread(task2).start();
System.out.println("A thread return result = " + task1.get()); //get()方法获取run()方法的返回值
System.out.println("B thread return result = " + task2.get());
}
}
public V get(long timeout,
TimeUnit unit)
throws InterruptedException,
ExecutionException,
TimeoutException
多线程常用操作方法
public static final int MAX_PRIORITY // 线程最高优先级,数值10
public static final int NORM_PROIORITY // 线程中等优先级,数值5
public static final int MIN_PRIORITY // 线程最低优先级,数值1
public final void setPriority(int newPriority) // 设置线程优先级
public final int getPriority() // 取得线程优先级
public static Thread currentThread();
public Thread(Runnable target, String name);
public final void setName(String name);
public final String getName();
public static void sleep(long millis) throw InterruptedException
进程在哪里?
每一个JVM运行就是一个进程,主方法只是其中一个线程,当一个类执行完毕,此进程会自动消失
- main线程:程序的主要执行,以及启动子进程。
- gc线程,负责垃圾手机
线程同步与死锁
线程同步
线程同步的两种方式
- 同步代码块:利用synchronized包装的代码块,但是需要指定同步对象,一般设置为this
- 同步方法,利用synchronized定义的方法
四种代码块:代码块、构造块、静态块、同步块
方法中完整的定义格式
[public | protected | private] [static] [final] [native] [synchronized] 方法返回值类型 方法名称(参数列表 | 可变参数)[throws 异常,异常 ...]
Object类对多线程的支持
// 线程等待
public final void wait() throws InterruptedException {}
// 唤醒一个线程
public final void notify() {}
// 唤醒全部等待线程
public final void notifyAll()
sleep()和wait()的区别?
- sleep()是Thread类中定义的static方法,表示线程休眠,将执行机会让给其他线程,但是监控状态依然保持,会自动恢复
- wait()是Object类中定义的方法,表示线程等待,一直到执行了notify()或notifyAll()后才结束等待
第十章 Java常用类库
StringBuffer类
String类
public final class String extends Object implements Serializable, Comparable<String>, CharSequence
StringBuffer类
public final class StringBuffer extends Object implements Serializable, CharSequence
关于CharSequence接口
接口里面提供了charAt()、length()方法
关于StringBuilder类、
和StringBuffer基本一样,只是StringBuffer类中定义的方法都是使用synchronized进行声明的,所以StringBuilder都是异步方法,线程不安全操作
Runtime类
在每一个JVM进程中,都会存在一个运行时的操作类的对象,而这个对象所属的类型几句是Runtime类
一些常用的方法
public static Runtime getRuntime()
public long maxMemory() // 返回最大可用内存大小
public long totalMemory() // 返回所有可用内存大小
public long freeMemory() // 返回所有空余内存大小
public void gc()
public Process exec(String command) throws IOException //创建新的进程
关于long型数据在两种情况下使用:表示文件可用内存大小,表示日期时间数字