java基础复习

基础总结

作用域:
成员变量:针对整个类有效。
局部变量:只在某个范围内有效。(一般指的就是方法,语句体内)
存储位置:
成员变量:随着对象的创建而存在,随着对象的消失而消失,存储在堆内存中。
局部变量:在方法被调用,或者语句被执行的时候存在,存储在栈内存中。
匿名对象
(1)匿名对象就是没有名字的对象。是对象的一种简写形式。
(2)应用场景
A:只调用一次类中的方法。
B:可以作为实际参数在方法传递中使用
构造方法:
构造方法没有返回值,方法名和类名一致,参数可有可无,当一个类中不声明构造方法,系统会默认声明一个无参构造方法。如果需要有参构造方法需要自己声明。
如果自定义类有构造方法,那么系统不会给出无参构造方法,这个时候我们可以不是无参构造方法,但如果需要使用无参构造,只能手动声明。
内存结构:
栈内存:用于存储局部变量,当数据使用完,所占空间会自动释放。
堆内存:数组和对象,通过new建立的实例都存放在堆内存中。
方法区:静态成员、构造函数、常量池、线程池
本地方法区:window系统占用
Person p = new Person();在内存中做了哪些事情:
(1)将Person.class文件加载进内存中。
(2)如果p定义在主方法中,那么,就会在栈空间开辟一个变量空间p。
(3)在堆内存给对象分配空间。
(4)对对象中的成员进行默认初始化。
(5)对对象中的成员进行显示初始化。
(6)调用构造代码块对对象进行初始化。(如果没有就不执行)
(7)调用构造方法对对象进行初始化。对象初始化完毕。
(8)将对象的内存地址赋值给p变量,让p变量指向该对象。
static关键字:
(1)静态的意思,用来修饰成员变量和成员函数
(2)静态的特点:
随着类的加载而加载
优先于对象存在
对所有对象共享
可以被类名直接调用
(3)静态的注意事项
A:静态方法只能访问静态成员
为什么:因为静态的内容是随着类的加载而加载,它是先进内存的。
B:静态方法中不能使用this,super关键字
C:主方法是静态的
public static void main(String[] args)
public:公共的意思,是最大权限修饰符。
static:由于jvm调用main方法的时候,没有创建对象。
只能通过类名调用。所以,main必须用static修饰。
void:由于main方法是被jvm调用,不需要返回值。用void修饰。
main:main是主要的意思,所以jvm采用了这个名字。是程序的入口。
String[]:字符串数组
args:数组名
在运行的时候,通过java命令给args数组赋值。
(4)静态变量和成员变量的区别
A:调用方式
静态变量也称为类变量,可以直接通过类名调用。也可以通过对象名调用。
这个变量属于类。
成员变量也称为实例变量,只能通过对象名调用。这个变量属于对象。
B:存储位置
静态变量存储在方法区长中的静态区。
成员变量存储在堆内存。
C:生命周期
静态变量随着类的加载而存在,随着类的消失而消失。生命周期长。
成员变量随着对象的创建而存在,随着对象的消失而消失。
D:与对象的相关性
静态变量是所有对象共享的数据。
成员变量是每个对象所特有的数据。
(5)静态的优点和弊端
优点:
对对象的共享数据进行单独空间的存储,节省内存,没有必要每个对象都存储一份
可直接被类名调用
弊端:
生命周期过长,随着类的消失而消失
访问出现权限,即静态虽好但只能访问静态
(6)什么使用使用静态呢?
A:当所有对象共享某个数据的时候,就把这个成员变量定义为静态修饰的。
B:当某个方法没有访问该类中的非静态成员,就可以把这个方法定义为静态修饰。
静态的生命周期比较长,所以一般不推荐使用。
(7)静态代码块
A:它只执行一次,它比main还先执行。
B:执行顺序
静态代码块–构造代码块–构造方法
继承:
(1)把很多类的相同特征和行为进行抽取,用一个类来描述。让多个类和这个类产生一个关系。
这样的话,多个类就可以省略很多代码。这个关系就是继承。java中用extends关键字表示。
(2)继承的体系结构
A:多个具体的对象,不断的向上抽取共享的内容,最终形成了一个体系。这个体系叫做继承体系。
B:继承体系的学习和使用原则
(3)继承的特点:
A:java中只能单继承,没有多继承。
B:java可以有多重(层)继承。
(4)继承的好处:
继承的出现提高了代码的复用性。
继承的出现让类与类之间产生了关系,提供了多态的前提。
(5)子父类中的成员关系
A:成员变量
在子类方法中使用一个变量时:
首先,在方法的局部变量中找这个变量,有则使用。
否则,在本类中找成员变量,有则使用。
否则,在父类中找成员变量,有则使用。
否则,报错。
B:成员方法
用子类对象使用一个方法时。
首先,在子类中找这个方法,有则使用。
否则,在父类中找这个方法,有则使用。
否则,报错。
final关键字
(1)最终的意思,可以用于修饰类,方法,变量。
(2)final修饰的类不能被继承。
final修饰的方法不能被重写。
final修饰的变量是一个常量。只能被赋值一次。
内部类只能访问被final修饰的局部变量。
抽象:
抽象类和抽象方法都必须由abstract修饰。
抽象类不一定有抽象方法,但有抽象方法的类一定是抽象类。
抽象类不能被实例化。
抽象特点:
A:抽象类中是否有构造方法?能不能被实例化?如果不能,为什么有构造方法?
抽象类中可以有变量和常量。
抽象类中可以有抽象方法和非抽象方法。
抽象类不能实例化,但可以给子类实例化使用。
abstract关键字不能和哪些关键字同事使用:
private私有子类不能继承,final修饰的方法不能被重写。抽象方法必须被重写,static修饰的可以通过类名调用,但抽象方法是没有方法体的。
接口和抽象类的区别
A:抽象类只能被单继承
接口可以多实现,接口的出现避免了多继承的局限性。
B:抽象类中的数据特点:
成员变量:可以是变量,也可以是常量
成员方法:可以是抽象方法,也可以是非抽象方法
构造方法:有构造方法
接口中的数据特点:
成员变量:是常量。默认修饰 public static final
成员方法:都是抽象方法。都有默认修饰 public abstract
构造方法:没有构造方法
try catch:
捕获异常信息,捕获异常原则先捕获小的,在不捕获大的。
finally是异常处理的关键字。必须执行的代码块,当在它执行之前,jvm推出则不执行。
当catch中有return,在return前执行finally代码块。
异常及其处理机制和常见的异常:
异常处理的关键字 throws 和 throw
异常的顶级父类是Throwable。
异常分为两种:一般性错误,在写代码是的错误Exception,RuntimeException运行时异常。
常见的异常:
java.lang.ArithmeticException算数异常。当运行时出现算术的错误(比如,除零)抛出。
java.lang.NullPointerException空指针异常。对null值调用属性和方法时抛出。
Java.long.ArrayIndexOutOfBoundsException 数组下标越界异常。当数组变量引用非法下标时抛出。
Java.long.NuberFormatException 数字格式化异常。当将字符串转成整形时,字符串中含有非数字的字符时抛出。
java.io.FileNotFoundException 文件未找到异常。当对文件进行操作时,错误的书写了文件路径时抛出。
java.sql.SQLException:Column “id2” not found 列名书写错误
java.sql.SQLException:Parameter index cut of range 占位符的数量和参数个数不匹配
com.mysql.jdbc.exceptions.jdbc4.MysqlSyntaxErrorException you have an error in your SQL syntax SQL语句书写错误
java.sql.SQLException: Parameter index out of range SQL语句占位符的数量和参数个数不匹配,检查一下问号的个数和是否是英文问号。
java.sql.SQLException : Column ‘id2’ not found 列书写错误

数据类型和装箱拆箱

八大基本数据类型:
byte 1字节 -128~127
short 2字节 -32768~32767
int 4字节 -2147483648~2147483647
long 8字节 -9223372036854775808 ~ 9223372036854775807
float 4字节 -3.4E38~3.4E38
double 8字节 -1.7E308~1.7E308
char 2字节 从字符型对应的整型数来划分,其表示范围是0~65535
boolean 1字节 true或false

基本数据类型的包装类:
byte → Byte
short → Short
int → Integer
long → Long
float → Float
double → Double
char → Character
boolean→ Boolean

Integer值范围-128~127之间时,返回的为int基本数据类型,当大于127后会new Integer对象。
例:

Douoble是浮点类型,所以数字是无限的,所以Double每次都创建对象。

进行归类:
Integer派别:
Integer、Byte、Short、Long、Character
取值范围:

Double派别:
Double、Float

包装类的equals方法首先将数据装箱,比较的是类型和数值两方面。

集合

ArrayList和LinkedList:
共同点:都是不同步的,线程不安全
不同:
ArrayList的基于动态数组实现,随机访问快,当超过数组长度,会扩充原来的50%,当在集合末尾插入和删除时与LinedList没有差别,当在集合里面插入和删除时效率不如LinkedList。默认ArrayList大小为10,超过则正常原来的3/2;

LinkedList基于链表的数据结构,查询是不能随机方位某个位置的数据,当在集合中添加和删除时,性能优于ArrayList。LinkedList是双向链表,没有初始容量和扩容机制。数据直接追加就行。

Vector:线程同步,当集合不足时,扩充原来的一倍,优于线程是安全的,所以性能较慢。初始容量是10。

哈希

Map:底层实现是数组和链表,使用hashcode和equals方法,保证存储的唯一性。
HashMap: 是非线程安全,key和value允许为null,其中key只允许有一个为null,value可以有多条记录为null;初始容量为16,扩容因子0.75(当前大小/当前容量 = 扩容因子),当达到扩容因子的阈值,则扩展为原来的2倍。
LinkedHashMap:存储是有顺序的。其他与HashMap一致。
HashTable:HashTable是线程安全的,相当于在整个Map加了一个大同步锁来保证线程的安全。key和value都不允许为空,否则会报错,HashTable的Lock锁住了整体。默认容量为1,加载因子0.75。扩容容量 = 原容量 * 2 + 1;
在这里插入图片描述

ConcurrentHashMap(jdk7版本):ConcurrentHashMap将Hash表默认分为16个桶(每一个桶可以被看作是一个Hashtable),ConcurrentHashMap的每个Segment可以看做是一个HashTable,所有ConcurrentHashMap的key和value都不可以为空,大部分操作都没有用到锁,而对应的put、remove等操作也只需要锁住当前线程需要用到的桶,而不需要锁住整个数据。采用这种设计方式以后,在大并发的情况下,同时可以有16个线程来访问数据,默认大小为16,阈值0.75。
在这里插入图片描述
jdk8版本的ConcurrentHashMap还没看,可以网上自己查找。

Set

基于HashMap实现,相当是HashMap的一个实例。
HashSet允许使用null元素,并保证存入数据不重复。
LinkedHashSet与HashSet一致,但是是有序的。

泛型

jdk1.5以后引入泛型的概念,主要的作用是将运行时遗产提前到编译时。
jdk1.7以后有泛型推断,右面声明不需要写泛型(仅左面写反省起作用)。
泛型类:

public class Generic<T> {
	T t;
	public void setT(T t) {
		this.t = t;
	}
	public T getT() {
		return t;
	}
}

泛型方法:

public class Generic {
	public <T> void setT(T t) {
		// 方法体
	}
}

泛型接口:

public interface Genenic<T , E>{
public void demo1(T t);
public void demo2(E e);
}

实现类的几种方式:

//1.都不添加泛型,默认泛型都为Object类型
public class GenenicImpl implement Genenic{
// 实现两个接口
}
//2.添加泛型,泛型为所添加的类型
public class GenenicImpl implement Genenic<String,String>{
// 实现两个接口
}
//3.实现类也不指定泛型
public class GenenicImpl<T , E> implement Genenic<T , E>{
// 实现两个接口
}

反射

反射简单来说就是程序运行时,获取程序一个的字节码文件,来获取这个类的所有属性和方法。反射的技术特性很强大,所以很多优秀的开源框架都用到了。
java反射创建类实例的三种方式:

// 首先创建一个Person类
public class Person{
	public String name;
	private Integer age;
}
public class Demo {
    public static void main(String[] args) {
        // 第一种方式
        // 由于已拿到对象,所以笔者认为没有必要再使用反射的方式(不推荐)
        Person person = new Person();
        Class person1 = person.getClass();
        System.out.println(person1);

        // 第二种方式
        // 这种方式虽然简洁,但需要导入依赖包,耦合高(不推荐)
        Class person2 = Person.class;
        System.out.println(person2);
        
        // 第三种方式
        // 这种方式完全解耦(推荐使用)
        Class person3 = null;
        try {
            person3 = Class.forName("Proxy.Person");
            System.out.println(person3);
        } catch (Exception e) {
        }
        
		// 课下小作业:下面都会输出什么结果?为什么?
        System.out.println(person1 == person2);
        System.out.println(person1 == person3);
        System.out.println(person2 == person3);
    }
}

其余的反射一般的用法都是通过api那对类中的对象或方法,进行使用,这些可以看java反射的api文档自行学习。

线程

进程:通俗的将就是一个应用程序,有独立的内存空间,一个进程至少有一个线程。
线程:进程的执行单元。
线程的几种状态:
1.New(新建状态)
2.Blocked(阻塞状态)
3.Runnable(运行状态)
4.Time_Waiting(睡眠状态)
5.Waiting(无限等待状态)
6.Terminated(死亡状态)
java中对线程主要的需求是实现多线程,主要有一下几种方式时间多线程:

// 第一种:实现Thread类,重写run方法
public class MyThread extends Thread {
    public MyThread() {}
    private String name;
    // 为了用名称区分线程,加入有参构造
    public MyThread(String name) {
        this.name = name;
    }
    @Override
    public void run() {
        // 实现功能
        for (int i = 0; i < 50; i++) {
            System.out.println(name + "-->" + i);
        }
    }
}
// 第二种方式 实现Runnable接口重写run方法
public class RunableDemo implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 1000; i++) {
        System.out.println(Thread.currentThread().getName() + "-->" + i);
        }
    }
}
// 第三种方式 实现callable接口,重写call方法
public class CallableDemo implements Callable {
    @Override
    public Object call() throws Exception {
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName() + "-->" + i);
        }
        return null;
    }
}
// 第四种线程池创建多线程可以实现Callable或Runnable
public class ThreadPool implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 50; i++) {
        System.out.println(Thread.currentThread().getName() + "线程池实现");
        }
    }
}
// 多线程测试类
public class TestThread {
    public static void main(String[] args) {
    	// 第一种实现方式的测试方法,查看打印结果
        MyThread myThread1 = new MyThread("小花");
        MyThread myThread2 = new MyThread("小李");
        myThread1.start();
        myThread2.start();
        
        // 第二种方式测试类
        Thread thread3 = new Thread(new RunableDemo());
        thread3.setName("小薛");
        Thread thread4 = new Thread(new RunableDemo());
        thread4.setName("小刘");
        thread4.start();
        thread3.start();

		// 第三种方法的测试类
		Callable<Object> oneCallable = new CallableDemo();
        Callable<Object> oneCallable1 = new CallableDemo();
        FutureTask<Object> oneTask = new FutureTask<>(oneCallable);
        FutureTask<Object> oneTask1 = new FutureTask<>(oneCallable1);
        Thread t = new Thread(oneTask);
        Thread t1 = new Thread(oneTask1);
        t.setName("小薛");
        t1.setName("小刘");
        t.start();
        t1.start();

		// 第四种方式测试
        // 创建线程池 并初始线程数
        ExecutorService executorService = Executors.newFixedThreadPool(5);
        for (int i = 0; i < 3; i++) {
        	// 将实现类方法
            ThreadPool threadPool = new ThreadPool();
            // 使用executorService执行Runnable的任务
            // 扩展:submit和execute实现的区别什么?
            executorService.submit(threadPool);
        }
        // 
        executorService.shutdown();
    }
}

对于继承Thread类和实现Runnable接口两种方式来说,通过实现接口的形式更加灵活:
①继承只能是单继承,实现则更加灵活。
②接口方式将run方法的方法体(线程任务)和开启线程的strat方法(开启线程)进行分离,使其接口,方便实现先成任务的切换。

Runnable和Callable区别:
①Runnable要实现run方法,Callable实现call方法。
②Runnable无返回值,Callable能返回执行结果。
③call方法可以抛出异常,run方法只能内部自行解决。

说到多线程,就不得不提到线程安全问题。最经典的线程安全问题就是抢票。

// 多线程抢票:
public class MyThread {
    public static void main(String[] args) {
        BuyTicket buyTicket= new BuyTicket();
        Thread t1 = new Thread(buyTicket);
        Thread t2 = new Thread(buyTicket);
        Thread t3 = new Thread(buyTicket);
        t1.start();
        t2.start();
        t3.start();

    }
}

// 使用Runnable,重写run方法,构建枪票代码
class BuyTicket implements Runnable {
    private int ticket = 100;
    @Override
    public void run() {
        while (true) {
            if (ticket > 0) {
            	// 为了提高异常发生概率 
                try {
                    Thread.sleep(20);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "出售第" + ticket + "票");
                ticket--;
            }
        }
    }
}

输出结果:
在这里插入图片描述
保证线程安全的几种方式:

// 同步代码块
public class MyThread {
    public static void main(String[] args) {
        BuyTicket buyTicket = new BuyTicket();
        Thread t1 = new Thread(buyTicket);
        Thread t2 = new Thread(buyTicket);
        Thread t3 = new Thread(buyTicket);
        t1.start();
        t2.start();
        t3.start();
    }
}

class BuyTicket implements Runnable {

    private int ticket = 100;
    // 同步锁  任意对象
    Object obj = new Object();

    @Override
    public void run() {
        while (true) {
            // synchronized锁的关键字 同步代码块
            synchronized (obj) {
                if (ticket > 0) {
                    try {
                        Thread.sleep(20);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + "出售第" + ticket + "票");
                    ticket--;
                }
            }
        }
    }
}
// 同步方法
public class MyThread {
    public static void main(String[] args) {
        BuyTicket buyTicket = new BuyTicket();
        // 验证锁对象是不是同一个BuyTicket对象
        // System.out.println("run :" + buyTicket);
        Thread t1 = new Thread(buyTicket);
        Thread t2 = new Thread(buyTicket);
        Thread t3 = new Thread(buyTicket);
        t1.start();
        t2.start();
        t3.start();
    }
}

class BuyTicket implements Runnable {

    private int ticket = 100;
    @Override
    public void run() {
    	// 验证锁对象是不是同一个BuyTicket对象
    	// System.out.println("this" + this);
        while (true) {
            // 同步方法
            safe();
        }
    }
	// 同步方法的锁对象就是 BuyTicket
    public synchronized void safe() {
        if (ticket > 0) {
            try {
                Thread.sleep(20);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "出售第" + ticket + "票");
            ticket--;
        }
    }
}
// 静态同步方法
public class MyThread {
    public static void main(String[] args) {
        BuyTicket buyTicket = new BuyTicket();
        Thread t1 = new Thread(buyTicket);
        Thread t2 = new Thread(buyTicket);
        Thread t3 = new Thread(buyTicket);
        t1.start();
        t2.start();
        t3.start();
    }
}

class BuyTicket implements Runnable {

    private static int ticket = 100;
    @Override
    public void run() {
        while (true) {
            // 同步方法
            safe();
        }
    }

    // 静态同步方法的锁对象就是本类的class对象 就是BuyTicket.class
    public static synchronized void safe() {
        if (ticket > 0) {
            try {
                Thread.sleep(20);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "出售第" + ticket + "票");
            ticket--;
        }
    }
}
// 使用Lock锁
public class MyThread {
    public static void main(String[] args) {
        BuyTicket buyTicket = new BuyTicket();
        Thread t1 = new Thread(buyTicket);
        Thread t2 = new Thread(buyTicket);
        Thread t3 = new Thread(buyTicket);
        t1.start();
        t2.start();
        t3.start();
    }
}

class BuyTicket implements Runnable {

    private static int ticket = 100;
    // 
    Lock lock = new ReentrantLock();

    @Override
    public void run() {
        while (true) {
            lock.lock();
            if (ticket > 0) {
                try {
                    Thread.sleep(20);
                    System.out.println(Thread.currentThread().getName() + "出售第" + ticket + "票");
                    ticket--;
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    lock.unlock();
                }
            }
        }
    }
}

Lock和synchronized优缺点:
synchronized是java语音自带的关键字,所以有内置特性,不需要手动去释放锁。
synchronized释放锁:
①占有锁的线程任务执行完。
②占有锁线程发生异常,jvm会自动释放锁。
③占有锁线程进入WAITING状态,调用wait()方法。
当使用synchronized关键字,占有锁的线程由于io等原因倒是线程阻塞(相当于sleep),那么会发生死锁,而lock可以设置超时时间。避免发生死锁现象。
多线程的情况下,读写文件时,读和写、写和写会发生冲突,但读和读是可以同时进行的,但使用synchronizedze只能有一个线程执行读操作。Lock有多线程的读操作机制。
Lock的tryLock()方法可以判断是否成功获取了锁,这个是synchronized无法办到的。

IO流

由于IO流总结起来太费时间,而且常用的也不是很多,所以借鉴一下大神的笔记。
链接: 应该是大神的笔记,学习一下
里面很详细的介绍了IO流。

java基础篇我个人感觉重要的算是总结完毕。
纯属自己总结,有错误的希望大家指出,不喜勿喷。谢谢了!~!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值