Java学习的基础概念和知识点
static
1、随着类的加载而加载
2、优先于对象存在
3、被所有对象所共享
4、可以直接被类名调用
使用注意:
1、静态方法只能访问静态成员
2、非静态成员可以访问静态成员
3、静态方法中不可以使用this、super关键字
this
1、方法间的相互调用
2、构造器相互调用,但是此时this必须写在构造方法的第一行
* package
* 1、提供类的多层命名空间,更好的管理代码结构,避免类名冲突
* 2、package必须写在文件的开头,必须写在import和类声明之前
* 3、com.jhtwl.erp.crm.domain
* erp是项目名,
* crm是erp项目中的模块名,
* domain是crm中的一层组件名;
* 4、包名的书写:全用小写字母,避免使用与系统发生冲突的名字
* java 常用的包介绍
* 1、java.long: 语言核心类,系统自动导入
* 2、java.util: Java工具类、集合框架和接口,包括:日历、时间、集合等
* 3、Java.net: 网络编程接口和类,和网络相关的类
* 4、Java.io: 流的接口和类:读写文件或图片
* 5、java.text: Java格式化相关类:国际化会用
* 6、java.sql: jdbc相关接口和类
* 7、java.awt: 抽象窗口工具集相关接口和类
* 8、java.swing: 图形用户界面相关接口和类
* 访问修饰符
* private 类访问权限:本类内部可以访问,不能继承到子类;
* default 什么都不写,包访问权限:本类内部可以访问,同包其他类也可以访问,同包可继承;
* protected 子类访问权限:本类内部可以访问,不同包的子类也可以访问,同包其他类也可以访问,能继承到子类;
* public 公共访问权限:任何地方都可以访问,能继承到子类
* 构造方法
* 方法名与类名相同
* 不同定义返回值类型
* 不需要写return语句
*
* 作用:给类中额字段进行初始化,可以用来创建对象
* setter方法和构造方法都可以用来初始化字段的值,那么什么时候用构造方法什么时候用setter?
* 1、当字段的值是和类的对象紧密相关不可分割的时候,用构造方法,就是说我要有这个实例,就必须有这个字段值,就用构造方法。
* 2、需要初始化的字段值不太多的时候可以用构造方法,如果字段值太多,构造方法的参数列表太长了。
* 3、其他时候都可以用setter方法。
* 类的设计
* 根据要求写出类所包含的字段;
* 所有的字段都必须私有化;
* 封装之后的字段可通过setter和getter设值和取得;
* 按需求可添加若干构造方法;
* 根据需求可添加相应的方法;
* 类中的所有方法都不要直接处理(输出打印),而是交给调用者去处理。
* 方法的覆写:当父类中某个方法不适合于子类时,子类出现父类一模一样的方法
* 子类方法前加上@Override能编译通过,表明是方法的覆写
* 调用被覆盖的父类方法:使用super.方法名(实参);
* 方法覆写时应遵循的原则
* 1、方法签名必须相同
* 2、子类方法的返回值类型比父类方法的返回值类型更小或相等
* 3、子类方法声明抛出的异常应比父类方法申明抛出的异常更小或相等
* 4、子类方法的访问权限应比父类方法更大或相等
*
* 方法重载和覆写的区别
* 构造方法的调用
* 1、Java在执行子类的构造方法前会先调用父类无参的构造方法,其目的是为了对继承自父类的成员做初始化操作
* 2、子类在创建对象的时候,默认调用父类的无参构造方法,要是子类构造方法中显示指定调用父类其他构造方法,就调用指定的父类构造方法,取消调用父类无参构造方法
this和super的区别
* 多态:编译时的类型由声明该变量时使用的类型决定,运行时的类型由实际赋给变量的对象决定,如果编译时类型和运行时类型不同,就出现多态
* 机制:父类的引用变量可以指向子类的实例对象,而程序调用的方法在运行期才动态绑定,就是引用变量所指向的真正实例对象的方法,也就是内存里正在运行的那个对象的方法,而不是引用变量的类型中定义的方法。
* 作用:把不同的子类对象都当作父类来看,可以屏蔽不同子类对象之间的差异,写出通用的代码,做出通用的编程,以适应需求的不断变化。
* 继承是多态产生的前提条件
* 分类:
* 1、编译时多态:方法重载
* 2、运行时多态:方法覆写
* 对象名 instanceof 类
* 判断指定的变量名此时引用的真正类型是不是当前给出的类或子类;
* Java基本数据的包装类:见图
* jdk1.5开始出现的特性:
* 1、自动装箱:可把一个基本类型变量直接赋给对应的包装类对象或则Object对象
* 2、自动拆箱:允许把包装类对象直接赋给对应的基本数据类型
* 普通代码块: 普通代码块就是直接定义在方法或语句中定义的代码块
* 构造代码块: 直接写在类中的代码块--> 优先于构造方法执行,每次实例化对象之前都会执行构造代码块
* 静态代码块: 使用static 修饰的构造代码块
* 特点:优先于主方法执行,优先于构造代码块执行,不管有创建多少对象,静态代码块只执行一次,可用于给静态变量赋值;
* 同步代码块:
* synchronized(obj) {
* // obj 表示同步监视器,是同一个同步对象
* }
* 单例模式:整个应用中有且只有一个实例,所有指向该类型实例的引用都指向这个实例
* 饿汉模式
* class Singleton {
* //在内部准备好一个对象
* private static Singleton instance = new Singleton();
* public static Singleton getInstance(){
* return instance;
* }
* private Singleton(){}
* public void show(){
* System.out.println("Singleton");
* }
* }
*
*
*
*
* 懒汉模式
* class Singleton{
* private static Singleton instance = null;
* public static Singleton getInstance(){ // 将instance传递到外部去
* if(instance == null){
* instance = new Singleton();
* }
* return instance;
* }
* private Singleton(){}
* }
* enum实现单例模式:
* 使用枚举来实现单例模式的好处是这样非常简洁,并且无偿地提供了序列化机制,绝对防止多次实例化,即使是在面对复杂的序列化或者反射攻击的时候
* public enum Singleton {
* INSTANCE;//唯一实例
* public static Singleton getInstance(){
* return INSTANCE;
* }
* public void show(){
* System.out.println("使用enum实现单例模式");
* }
* }
* final关键字
* 1、可以修饰类、方法、变量
* 2、修饰的类不可以被继承,但是可以继承其他类
* 3、修饰的方法不可以被覆盖,但可以覆盖父类方法
* 4、修饰的变量被称为常量,这些变量只能赋值一次
* 5、内部类在局部时,只可以访问被final修饰的局部变量
* final修饰的引用类型常量,表示变量的引用不能变,而不是该变量的值不能变
* 常量名称所有字母大写,若有多个单词组成,单词间使用下划线连接。
* public static final 修饰的常量称为全局常量
* public static final double PI = 3.1415926;
* abstract 关键字
* 通过abstract关键字来修饰的类称为抽象类;
* 可以定义被abstract修饰的抽象方法
* 抽象方法只有返回类型和方法签名,没有方法体
* 抽象类不能创建实例对象(不能new)
* 需要子类覆盖掉所有的抽象方法后才可以创建子类对象,否则子类也必须作为抽象类
* 列举常见的几个抽象类:流的四个基本父类
* InputStream,OutputStream,Reader,Writer
* interface 接口
* [修饰符] interface 接口名 extends 父接口1,父接口2....
* 特点:
* 没有构造方法,不能实例化
* 接口里没有雨普通方法,方法全部是抽象的
* 接口只能继承接口,不能继承类
* 接口里的方法默认修饰符是public abstract
* 接口里的字段全是全局常量,默认修饰符是public static final
* 接口里的成员包括:(主要是前两个)
* 全局常量
* 公共的抽象方法
* 内部类(包括内部类。内部接口、内部枚举类);
* 使用接口:
* public class ClassName extends SuperClassName implements IA,IB
* [修饰符] class 类名 implements 接口1,接口2...
* 实现接口的方法必须是 public 类型
* 接口和抽象类
* 相同点:
* 1、都位于继承的顶端,用于被其他实现或继承;
* 2、都不能实例化;
* 3、都包含抽象方法,其子类都必须覆写这些抽象方法;
* 区别:
* 1、抽象类为部分方法提供实现,避免子类重复实现这些方法,提供代码重用性;接口只能包含抽象方法;
* 2、一个类只能继承一个直接父类(可能是抽象类),却可以实现多个接口;(接口弥补了Java的单继承)
*
* 二者的选用:
* 1、优先选用接口,尽量少用抽象类
* 2、需要定义子类的行为,又要为子类提供共性功能时才选用抽象类
* 异常体系
* Throwable
* Error:
* 通常指JVM出现重大问题如:运行的类不存在或者内存溢出等
* 不需要编写针对代码对其处理,程序无法处理。
* Exception:
* 在运行时运行出现的一些情况,可以通过try,catch,finally处理
* 处理异常的5个关键字:try, catch, finally, throw, throws
* 捕获异常:先捕获小异常再捕获大异常
*
* 异常处理格式
* try {
* // 可能出异常的代码
* } catch (异常类 对象) {
* // 处理异常的代码
* } finally {
* // 一定会执行的代码
* }
* 当try语句块出现异常,程序会自动跳到catch语句块去找匹配的异常类型,并执行异常处理语句,finally语句块是异常的统一出口。
*
* Throwable中的方法
* String getMessage() // 获取异常信息,返回字符串
* String toString() // 获取异常类名和异常信息,返回字符串
* Void printStackTrace() // 打印异常在堆栈的跟踪信息
*
* 异常分类:
* Java.lang.Object -> java.lang.Throwabel -> java.lang.Exception -> java.lang.RuntimeException
* 编译时被检查异常 --> Checked异常 程序中使用try...catch处理
* 编译时不被检测的异常 --> Runtime异常 可以不用try...catch处理,出现异常有JVM处理
*
* throws
* 在可能出现异常的方法上声明抛出可能出现异常的类型
* 声明的时候尽可能声明具体的异常,方便更好的处理
* 当前方法不知道如何处理这种异常,可将该异常交给上一级调用者来处理(非RuntimeException类型的异常)。
* 方法一旦使用throws声明抛出方法内可能出现的异常类型, 该方法就可以不再过问该异常了
* 一个方法调用另一个使用throws声明抛出的方法,自己要么try...catch , 要么也throws
* public 返回值类型 方法名(参数列表...) throws 异常类A, 异常类B ... {
* }
*
* throw
* 自行抛出一个异常对象,抛出异常类的对象
* 若throw抛出的是Runtime异常:
* 程序可以显示使用try...catch来捕获并处理,也可以不管,直接交给方法调用者处理
* 若throw抛出Checked异常
* 要么放在try里自己处理,要么放在一个throws声明的方法里面,交给调用者处理
* public static void main(String args[]) {
* try {
* fnl(1);
* } catch (Exception e) {
* e.printStackTrace();
* }
* fn2(2);
* }
* public static void fn1(int a) throws Exception {
* if (a > 0) {
* throw new Exception("fn1 -- a 值不合法");
* }
* }
* public static void fn2(int a) {
* if (a > 0) {
* throw new RuntimeException("a值不合法");
* }
* }
*
* throws & throw
* 1、throws用于在方法上声明该方法不需要处理的异常类型
* 2、throw用于抛出具体异常类的对象
* 3、throws与throw的区别
* 1、thorws用在方法上,后面跟异常类名,可以是多个异常类
* 2、throw用在方法内,后面跟异常对象,只能是一个。
*
* finally
* 1、不管try块程序是否异常,也不管哪个catch执行,finally块总会执行
* try语句块或会执行的catch语句块使用了JVM系统退出语句例外;//System.exit(1)
* 2、try块必须和 catch块或和finally同在,不能单独存在,二者必须出现一个
* 3、不要在finally中使用return 或throw语句,否则将会导致try、catch中的return或throw失效
*
* 自定义异常
* 自定义类继承Exception或者其子类
* 1、一般的我们继承RuntimeException
* 2、提供无参构造方法和带一个参数的构造方法
* 使用自定义异常:
* 1、通过构造方法指定具体的异常原因
* 2、通过throw将自定义异常抛出,交给调用者处理
* class MyException extends Exception {
* public MyException( String message) {
* super(message);
* }
* public MyException(){}
* }
* String:不可变
* 常量池:JVM中一块独立的区域存放字符串常量和基本类型常量(public static final)
* String对象比较
* 1、单独使用""引号创建的字符串都是常量,编译期就已经确定存储到常量池中
* 2、使用new String("")创建的对象会存储到堆内存中,是运行期新创建的
* 3、使用只包含常量的字符串连接符如"aa" + "bb"创建的也是常量,编译期就能确定,已经确定存储到常量池中
* 4、使用包含变量的字符串连接符如"aa" + s1创建的对象是运行期才创建的,存储在堆中
*
* StringBuffer & StringBuilder
* StringBuffer: 是线程安全的
* StringBuilder: 是线程不安全的,性能高点,推荐使用
* StringBuffer:的字符序列是可变的
* StringBuffer 和 String之间的转换:
* String toString() 返回此序列中数据的字符串表示形式
* StringBuffer(String str):以指定的字符串创建StringBuffer对象
* 多线程
* 继承Thread类
* 1、子类覆写父类中的Run方法,将线程运行的代码存放在run中
* 2、建立子类对象的同时线程也被创建
* 3、通过调用start方法开启线程
* 实现Runnable接口
* 1、子类覆盖接口中的run方法
* 2、通过Thread类创建线程,并将实现了Runnable接口的子类对象作为参数传递给Thread类的构造函数
* 3、Thread类对象调用start方法开启线程
* 两种方式的比较
* A extends Thread:
* 简单、不能再继承其他类了(Java单继承)、同份资源不共享
* A implements Runnable(推荐):
* 多个线程共享一个目标资源,适合多线程处理同一份资源、该类还可以继承其他类,实现其他接口
* I/O
*
* InputSteam和Reader是所有输入流的基类,他们都是抽象类
* 一般来说处理字符或字符串时使用字符流,处理字节或二进制对象时应使用字节流
* 字节流: 输入流OutputStream 输出流InputStream
* 字符流: 输入流Reader 输出流Writer
* 字节 --> 字符转换流
* OutputStreamWriter:把字节输出流对象转成字符输出流对象
InputStreamReader:把字节输入流对象转成字符输入流对象
FileWriter和FileReader分别是OutputStreamWriter和InputStreamReader的直接子类,而不是Writer和Reader的直接子类,区别于FileInputStream 和InputStream。
注:无论使用字节流还是字符流实际上在内存中最终都是通过字节的形式来操作流的。
字节流和字符流的区别
在进行字符流操作的时候会使用到缓冲区,而字节流操作的时候是不会使用到缓冲区的。
在输出的时候,OutputStream类即使最后没有关闭内容也可以输出。但是如果是Writer的话,则如果不关闭,最后一条内容是无法输出的,因为所有的内容都是保存在了缓冲区之中,每当调用了close()方法就意味着清空缓冲区了。那么可以证明字符流确实使用了缓冲区:
字节流:程序 → 文件
字符流:程序 → 缓冲区 → 文件
如果现在字符流即使不关闭也可以完成输出的话,则必须强制性清空缓冲区:
方法:public void flush() throws IOException
两者相比,肯定使用字节流更加的方便,而且在程序中像图片、MP3等都是采用字节的方式的保存,那么肯定字节流会比字符流使用的更广泛。
但是需要说明的是,如果要是想操作中文的话,字符流肯定是最好使的。