基础知识
计算机发明者 约翰·冯·诺依曼
计算机由硬件系统和软件系统组成,没有安装任何软件的计算机成为裸机
软件:按照特定顺序组织的计算机数据和指令的集合
软件分为系统软件和应用软件,先有系统软件,才可以安装应用软件
JAVA
java之父-----詹姆斯高斯林
1991年出现
Java语言平台版本
J2SE/JAVASE -- 标准版/基础班
JSME/JAVAME -- 微型版/移动版
JSEE/JAVAEE -- 企业版/商务版
Java语言特性
简单性,高性能,编译性,解释性,分布式处理,健壮性,安全性,面向对象,开源,跨平台
配置环境变量
1.新建JAVA_HOME jdk的根目录
2.新建CLASS_PATH jdk的lib目录
3.修改Path 最后加上jdk的bin目录 用:隔开
4.java -version测试
JVM,JRE和JDK
JVM -- 运行.java文件编译后的.class字节码文件--JVM将JAVA代码转换为对应的操作系统可以理解的指令,不同的操作系统有不同的虚拟机与之对应,同一段代码交给虚拟机之后,虚拟机再转化给操作系统
JRE -- 运行时环境--运行java程序最小的环境为JRE
JDK -- 开发工具包--开发java程序最小的环境为JDK,所以JDK是JAVA语言的核心
面向对象三大特征
封装:把相关的数据封装成一个"类"组件,被private修饰的成员变量和方法实现了私有化,访问权限只能在本类中访问
继承:是子类自动共享父类的属性和方法,这是类之间的一种关系
多态:增强软件的灵活性和重用性
在一个java文件中可以写多个class,但是被public修饰的只能有一个,而且这个公共类的名字必须与文件名保持一致
构造方法是一种特殊的方法,他是一个与类同名且没有返回值类型的方法
代码快之间的执行顺序
静态代码快->构造代码快->构造方法->局部代码快
为什么是这样的顺序呢?
静态代码快要优先于对象进行加载,是随着类的加载而加载到内存中,静态资源只加载一次就会一直存在,直到类消失,它才会消失
每个元素的作用?
静态代码快:专门用来完成呢一些需要在第一时间加载且只加载一次的资源
构造代码快:创建对象时才会触发,用来提供构造方法中的共性内容
构造方法:创建对象时调用,用来创建对象,在构造代码快之后执行
局部代码快:调用其所在方法时才会执行,用于控制变量的作用范围
多态是什么?
同一种事物多种表现形式,可以把多种子类都当做父类来看,统一标准
实现多态的前提?
继承+重写
多态的特点?
父类引用指向子类对象
编译看左边,运行看右边
多态的使用?
多态中,成员变量使用的是父类的
多态中,成员方法使用的是父类的声明,子类的实现
abstract
抽象类中可以有构造方法
父类的构造方法优先于子类执行
抽象类不可以被实例化
抽象类中存在构造方法不是为了创建本类对象时调用的,而是为了创建子类对象时调用
如果一个类中都是普通方法,为什么还要被声明抽象类呢?
原因:抽象类不可以创建对象
所以如果不想让外界创建本类的对象,就可以把普通类声明成抽象类
子类创建对象时,默认会调用父类的无参构造,目前接口实现类的父级是一个接口,而接口中没有构造方法,那实现类构造方法中的super()调用的是谁呢?
结论:如果一个类没有明确指定父类,那么默认继承顶级父类object,所以super()会自动调用object类中的无参构造
接口中的变量实际都是静态常量,可以被类名直接调用
接口中的变量实际都是静态常量,值不可以被修改
Object
每个类都使用Object作为超类,也就是我们所说的"顶级父类'
当一个类没有明确指定父类时,默认以Object作为其父类
1)toString(): 默认实现返回的是地址值,重写后打印 对象类型+属性值
2)hashCode(): 返回对应对象的哈希码值
3)equals(): 默认实现==比较,比较的是地址值
Student重写后比较的是类型+所有属性值一致就返回true
String默认重写了equlas(),它比较的是两个串的具体内容
如果想要查看对象的属性和属性值,那么需要重写Object的toString()
String
String底层是char[]
1)准备char数组存储数据,然后将这个数组传给String的构造函数创建对象
2)String s = "abc"; 此种有高校的效果,在堆中常量池
首次创建时新建,第二次不再新建,到常量池中找数据直接使用
自动装箱:编译器会自动把基本类型包装成对应的包装类型,自动装箱底层发生的代码Integer.valueOf();valueOf()的方向: int -> Integer
自动拆箱:从包装类型的值,自动变成基本类型的值,自动拆箱底层发生的代码:**.intValue();intValue()的方向:Integer -> int
IO流
根据单位分分为字节流和字符流
字节流:针对二进制文件,可以处理多媒体数据
InputStream
OutputStream
字符流:针对文本文件
Reader
Writer
高效流高效的原因在于底层维护了一个byte[],8192大小
序列化和反序列化
序列化:把对象序列化后保存到磁盘中(比如文件) ObjectOutputStream
反序列化:读取磁盘中序列化的数据,重新恢复对象 ObjectInputStream
泛型
泛型是JDK1.5的一个新特性,通常用来和集合对象一起使用
泛型概念非常重要,它是程序的增强器,它是目前主流的开发方式
泛型不可以使用基本类型,只能使用引用类型
集合
集合:存放多个数据的容器
Collection 父级接口
List(子级接口)有顺序,可重复 根据索引操作时用
ArraysList(实现类)底层是数据结构,查询快,增删慢,适合查询较多的场景
LinkedList(实现类)底层是链表结构,查询慢,增删快,适合增删操作较多的场景
Set(子级接口)无顺序,不可重复 给元素去重用
HashSet(实现类)
Map(接口) 数据要符合映射规则,一定注意要同时指定K 和 V的数据类型,至于是什么类型,自己定义
Map中存放的都是无序的数据
Map中的key不可以重复,如果重复,此key对应的value会被覆盖
HashMap(实现类)
迭代(遍历)方式一:转成set集合,set中存着的是map的key-->keySet()
迭代(遍历)方式二:转成set集合,set中存着的是Entry,Entry就是一对键值对
线程
线程的概念:
线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位
实现多线程的两种方式的区别
1. 继承Thread类
优点:编写简单,如果需要访问当前线程,无需使用Thread.currentThread()方法,直接使用this即可获得当前线程
缺点:自定义的线程类已继承了Thread类,所以后续无法再继承其他的类
2.实现Runnable接口
优点:自定义的线程类只是实现了Runnable接口或Callable接口,后续还可以继承其他类,在这种方式下,多个线程可以共享同一个target对象,所以非常适合多个相同线程来处理同一份资源的情况,从而可以将CPU 代码 还有数据解耦,形成清晰的模型,较好的提现了面向对象的思想
缺点:编程稍微复杂,如想访问当前线程,则需使用Thread.currentThread()方法
多线程安全问题是如何出现的?
常见情况是由于线程的随机性+访问延迟
以后如何判断程序有没有线程安全问题?
在多线程程序中+有共享数据+多条语句操作共享数据
ExecutorService:用来存储线程的池子,把新建线程/启动线程/关闭线程的任务都交给池来管理
Executors:用来创建线程池对象的工具
newFixedThreadPool(5):表示创建含有5个线程数的池子
pool.execute(target):让线程池中的线程来执行任务,每次调用都会启动一个线程,本方法的参数就是要执行的目标业务target
元注解:
@Target 表示自定义注解可以使用的位置:类上 方法上 属性上等等 使用注解时需要导包,通过"ElementType.静态常量值"的方式来指定,如果有多个值,使用{ , }的格式来写
@Retention 注解的生命周期:源文件中 字节码文件中 运行中
使用注解时需要导包,通过RetentionPolicy.静态常量值来指定此自定义注解的生命周期,值只能有一个
自定义注解的语法与java不同,不要套用java的格式
定义注解要用 @ interface 注解名 的方式来定义
单例设计模式
构造方法和对象私有化后,通过公共的访问点来获取对象,那外界如何调用这个公共方法呢?
之前我们都是在外部创建本类对象并进行方法调用,但是现在单例程序中外部无法直接创建本类对象
解决方案:我们可以利用之前学习的静态的概念,将方法修饰成静态的,就可以通过类名直接调用
注意事项:静态只能调用静态,所以静态方法中返回的对象也需要用静态修饰
关于单例设计模式的两种实现方式:
1.饿汉式(简单安全):不管你用不用这个类的对象,都会直接先创建一个
面试重点
2.懒汉式(不简单不安全):先不给你创建这个类的对象,等你需要的时候再帮你创建---利用了延迟加载的思想
延迟加载:是指不会在第一时间就把对象创建好来占用内存,而是什么时候用到,什么时候再去创建对象
线程安全问题:是指共享资源有线程并发的数据安全隐患,可以通过加锁的方式[同步代码快/同步方法]
反射
Reflection(反射)是Java程序开发语言的特征之一,它允许运行中的Java程序对自身进行检查----"自审""自省"
反射需要用到的API
获取字节码对象(反射核心):
Class.forName("类的全路径");
类名.class
对象.getClass();
常用方法
获取报名,类名
clazz.getPackage().getName()//包名
calzz.getSimpleName()//类名
clazz.getName();//完整类名
通过单元测试来反射创建对象
方式一:通过字节码对象直接调用newInstance(),触发无惨构造来创建对象
方式二:先获取指定的构造函数,再通过构造函数对象调用newInstance,触发对应类型的构造函数来创建对象