Java基础

JAVA

一、基础语法

冯·诺依曼体系结构

在这里插入图片描述

1.基础数据类型

  1. 整数:byte(1位)、short、int、long
  2. 浮点型:float、double
  3. 字符:char(2位),可存一个汉字
  4. boolean:true/false(默认值是false)(1为)

Java中整数默认为int,浮点数默认为double
JDK7.0新特性:数字可以用_分割,输出正常数字

int money = 100_000_000;

二进制在数字前加0b、八进制在数字前加0、十六进制在数字前加0x

银行业务不能用浮点数进行计算,因为有精度损失和舍入误差,还有范围会溢出 (最好完全避免使用浮点数进行比较)

一般都是使用BigDecimal进行计算

2.数据转换

  • 强制转换:高–>低
  • 自动转换:低–>高
  • 注意:
    1. 不能对布尔值进行转换
    2. 不能把对象转化成不相干的类型
    3. 转化时可能存在内存溢出或精度问题
定义常量
final static int PI = 1; //final和static是修饰符,前后顺序不影响

3.运算符

  1. instanceof:判断一个对象是否是一个类的实例
  2. &&和||:有短路的特性,&&如果前面错误就不会计算后面的表达式了,||是前面正确就不会计算后面的了
  3. 整数相加,如果没有long型,结果全为int

4.方法

  1. 重载:方法名一样,参数(个数、类型、顺序)不一致为重载,与返回值无关
  2. 可变参数(不定项同类型参数):一个方法只能有一个可变参数,且只能是形参的最后一个参数
public class Main {

    public static void main(String[] args) {
        Main main = new Main();
        main.test(1,2,3,4);
    }
    public void test(int... a){
        for (int i:a){
            System.out.println(i);
        }
    }
}
  1. 递归:两个部分 (java是栈机制)
    • 递归头:什么时候不调用自己,如果没有头,就会死循环
    • 递归体:什么时候调用自己
//5! 5*4*3*2*1
//1! 1
//2! 2*f(1)
//3! 3*f(2)
public int f(int n){
    if(n == 1){
        return 1;
    }else{
        return n*f(n);
    }
}

在这里插入图片描述

  1. 内存分析:
    • 栈:存放基本变量,定义的变量(引用)(person)
    • 堆:存放new出来的对象数组(分配具体的内存)(new Person())
Person person = new Person();
  1. 冒泡排序优化:定义一个flag=false,设置冒泡时flag=true,如果数组已排序,直接跳出
    在这里插入图片描述

  2. 稀疏数组

二、面向对象

2.1简介

类是对象的抽象,对象是类的具体

  1. 本质:以类的方式组织代码,以对象的方式封装数据
  2. 三大特性:抽象(所有编程语言都有的特点,不算面向对象的特有的性质,从众多的事物中抽取出共同的、本质性的特征),三大特征都是为了抽象
    • 封装

      • 提高程序安全性,保护数据
      • 隐藏代码的具体实现
      • 提供接口访问
      • 属性私有,提高了系统可维护性;在真实开发中,可以在set中限定一些不安全的情况(使用if判断)
    • 继承:子类具有父类的全部特性(ctrl+H) 可查看当前类的继承关系,java只有单继承

      • super()调用父类的构造函数,必须在第一行
      • super()和this不能同时调用构造函数
      • 重写,方法名和参数列表必须相同,返回值类型也必须相同,修饰符范围可以扩大,抛出的异常可以缩小

      假如A继承了B

      A a = new A();//a,b(变量),就叫引用,new的就叫对象
      a.test();
      B b = new A();//(相当于父类指向子类对象)
      b.test();
      //如果test是静态方法(static修饰),a.test是子类的方法,b.test是父类的方法,如果test不是静态方法,则都是调用子类的方法
      //如果子类有非重写的方法test1(),则b.test1()会报错(强制类型转化就可以)
      
    • 多态:多态是方法的多态,属性没有多态。(属性是静态的数据,方法是动态的行为),多态存在的条件:

      • 有继承关系
      • 子类重写父类方法
      • 父类指向子类对象:B b = new A();
      • instanceof判断一个对象是否是某类的实例对象或者父类
      • 把子类转成父类,向上转型,默认转换,可能会丢失一些方法(非父类的重写方法)
      • 父类转成子类,向下转型,强制转换
    • 修饰符

      • public
      • protected:
        • 子类与基类在同一包中可访问
        • 在不同包:子类实例可以访问其从基类继承而来的protected方法,而不能访问基类实例的protected方法。就是在父类包下实例化可以访问,在子类包中实例化不能访问(编译错误)
      • default
      • private
        在这里插入图片描述

2.2代码块

  • 静态代码块:只在类加载的时候执行一次,最先执行
  • 匿名代码块和构造函数:实例对象的时候执行,匿名先执行
{
    System.out.println("no name");//匿名代码块,一般赋初值
}
static {
    System.out.println("static");//静态代码块
}
  • 导入静态包,可直接使用包中的方法
import static java.lang.Math.random;
public static void main(String[] args) {
    System.out.println(random());
}
  • 静态变量会先分配地址空间设置为默认值,然后再看静态代码块和定义的静态变量上下位置赋初始值,按上下位置执行。

2.3 抽象类

  • 抽象类的非抽象子类必须实现抽象类的所有抽象方法
  • 不能被实例,只能靠子类实现
  • 抽象方法(相当于一种规范)必须写在抽象类中,可以写普通的方法
  • 抽象类有构造方法,接口没有

2.4. 接口

  • 接口中所有方法都是public abstract,抽象的,比抽象类更抽象
  • 接口中定义属性都是常量,public static final修饰
  • 类只能单继承,而类可以实现多个接口,相当于伪多继承
  • 接口中不能有构造函数
  • 只有一个抽象方法的接口叫函数式接口,可使用Lambda表达式实现
public interface Abs {
    public abstract void test(String message);
}
public static void main(String[] args) {
    //Abs abs = () -> System.out.println("test");//无参
    Abs abs = message -> System.out.println("test"+message);//有参
    abs.test("dasd");
}

2.5 内部类

  • 类里面再定义类,可以调用外部类的私有属性
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();
  • 一个类可以定义多个类,但只能有一个public的类
  • 方法类也可定义类,局部内部类
  • 匿名内部类
public class test {
    public static void main(String[] args) {

        Service service = new Service() {//匿名内部类
            @Override
            public void hello() {
                System.out.println("service");
            }
        };
    }
}
interface Service{
    void hello();
}

2.6 Error和Exception(快捷键Ctrl+alt+t)

在这里插入图片描述

  • 检查性异常:用户错误使用或问题引起的,程序员无法预见的,如打开不存在的文件
  • 运行时异常:可在程序编译时忽略,可以被程序员避免的异常,Exception一般程序可以处理,尽可能在程序中处理
  • 错误:编译检查不到,如栈溢出,由JVM虚拟机生成抛出,是程序无法控制和检查的,产生了一般由JVM终止线程
  • 自定义异常:直接继承Exception,然后实现构造函数和toString()方法就行
  • try-with-resource机制:try(){}catch(){},将要关闭的外部资源在()中创建,catch()捕获处理异常。不用finally关闭资源

2.7 Date类

  • 一般用Calendar类代替Date类
    Calendar类是一个抽象类,且Calendar类的构造方法是protected的,API中提供了getInstance方法用来创建对象。
  • SimpleDateFormat:用户可自定义日期的输出格式
public static void main(String args[]) {
   Date now= new Date();
   SimpleDateFormat ft = new SimpleDateFormat ("yyyy-MM-dd hh:mm:ss");
   System.out.println("当前时间为: " + ft.format(now));
   //当前时间为: 2018-09-06 10:16:34
}

2.8String类

  • String不可变字符序列,少量字符串时使用
  • StringBuffer:可变字符序列、效率低、线程安全
  • StringBuilder:可变字符串,效率高、线程不安全

2.9 集合框架

Collection接口:储存可重复,无序

  • List:接口,继承Collection,可重复,有序,查找效率高,插入效率低,可插入null
    • ArrayList:常用,遍历提供更好的性能,非同步,多线程不要使用
    • LinkedList:没有同步方法,多线程时,需要自己实现同步
  • Set:接口,继承Collection,不可重复,无序,查找效率低,插入、删除效率高,可插入null
    • HashSet:常用
    • TreeSet:可实现排序

Map:接口,储存键值对

  • HashMap:它根据键的hashCode值存储数据,允许一个键为null,不支持线程同步;需要满足线程安全,可以用 Collections的synchronizedMap方法使HashMap具有线程安全的能力,或者使用ConcurrentHashMap。

  • Hashtable:Hashtable是遗留类,很多映射的常用功能与HashMap类似,不同的是它承自Dictionary类,并且是线程安全的,任一时间只有一个线程能写Hashtable,并发性不如ConcurrentHashMap,因为ConcurrentHashMap引入了分段锁。Hashtable不建议在新代码中使用,不需要线程安全的场合可以用HashMap替换,需要线程安全的场合可以用ConcurrentHashMap替换。

  • LinkedHashMap:LinkedHashMap是HashMap的一个子类,保存了记录的插入顺序,在用Iterator遍历LinkedHashMap时,先得到的记录肯定是先插入的,也可以在构造时带参数,按照访问次序排序。

  • TreeMap:TreeMap实现SortedMap接口,能够把它保存的记录根据键排序,默认是按键值的升序排序,也可以指定排序的比较器,当用Iterator遍历TreeMap时,得到的记录是排过序的。如果使用排序的映射,建议使用TreeMap。在使用TreeMap时,key必须实现Comparable接口或者在构造TreeMap传入自定义的Comparator,否则会在运行时抛出java.lang.ClassCastException类型的异常。

HashMap

  • 使用哈希表来存储的。哈希表为解决冲突,可以采用开放地址法和链地址法、再哈希、建立公共溢出区,Java中HashMap采用了链地址法。
  • HashMap初始长度为16,负载因子为0.75,最大容量为16*0.75,大于这个值就会开始扩容,一般为增加一倍,长度为2的n次方
  • 从结构实现来讲,HashMap是数组+链表+红黑树(JDK1.8增加了红黑树部分)实现(产生Hash冲突(hash相等,key值不一样)就放在链表上,链表长度大于8自动转成黑红树,黑红树小于6自动转成表)

Collections

  • 一个工具类,可实现集合的排序、基本查找、反转、复制和同步控制等功能
  • 线程安全:Vector(list)、HashTable(map)(主要是因为实现同步耗费资源很大)

2.10 IO

  • 字节流:大型文件用流处理,一般读取二进制,一个字节
    • OutputStream
    • InputStream
  • 字符流:两个字节,一般读取字符
    • Reader
    • Writer
  • 节点流:CharArray:可以从或向一个特定的地方(节点)读写数据
  • 处理流:是对一个已存在的流(字符/字节)的连接和封装,通过所封装的流的功能调用实现数据读写。
    • Buffer
    • Data
    • 转换流:InputStreamReader,OutputStreamWriter,字节转换为字符
    • Filter
    • Print
  • 关键字:transient,设置透明,不会被序列化,节省空间
transient int modCount;

2.11 正则表达式

//判断字符串是否符合某个格式
public static void main(String[] args) {
    String pattern="\\w{0,}\\@\\w{0,}\\.{1}\\w{0,}";//正则表达式(一个由一系列元字符组合成的字符串)
    System.out.println("22222222@qq.com".matches(regularExpression));
}
  1. 泛形
  • 默认使用方法
// 泛型方法 printArray,调用时只能使用引用数据类型(对象)
public < E > void printArray( E[] inputArray ){
    // 输出数组元素
    for ( E element : inputArray ){
        System.out.printf( "%s ", element );
    }
    System.out.println();
}
  • 限制类型
public static <T extends Comparable<T>> T maximum(T x, T y, T z){                     
  T max = x; // 假设x是初始最大值
  if ( y.compareTo( max ) > 0 ){
     max = y; //y 更大
  }
  if ( z.compareTo( max ) > 0 ){
     max = z; // 现在 z 更大           
  }
  return max; // 返回最大对象
}
  • 类型通配符:?代替具体的类型参数。例如 List<?> 在逻辑上是List< String >,List< Integer > 等所有List<具体类型实参>的父类。

二、网络编程

协议
在这里插入图片描述

  • 五层协议是把会话层及以上包括至应用层
  1. 简介
  • 计算机网络
    把不同地方的计算机通过协议连接起来。
  • 网络编程的目的
    数据交换、通信
  1. 入门
  • 端口:表示计算机上的一个程序的进程
    • TCP和UDP是两个不同的协议,每个协议都有65535个端口,TCP和UDP可同时使用80端口,单个协议下端口号不能冲突
    • https端口:443 ,http:80
  1. 通信协议
  • TCP:连接需要三次握手 四次挥手,安全连接,面向连接

    最少需要三次,保证稳定连接
    //三次挥手
    A:你瞅啥?
    B:瞅你咋地?
    A:干一场!
    //四次挥手
    A:发送一个数据,我需要断开连接,断开A->B数据传输
    B:收到数据包,断开了B->A的数据传输
    B:发送数据,表示我知道了,已断开数据传输
    4.A:收到数据,断开TCP连接
    

    四次挥手为何不是三次的原因是:三次挥手只能断开双方的数据传输,不能断开TCP连接

    Windows默认编码是GBK,而不是UTF-8

  • UDP:不安全连接,面向数据报

三、多线程

状态
在这里插入图片描述

  1. 进程和线程的区别
  • 进程:在操作系统中运行的程序,比如QQ、播放器、游戏、IDE
    进程就是程序的一次执行过程,是资源分配的基本单位,一个进程包含多个线程
  • 线程:比如看电影时:一个线程控制声音,一个线程控制图像,另一个控制字幕
    真正执行的是线程,线程是CPU调度和执行的基本单位

注意:很多多线程都是模拟出来的,真正的多线程是指有多个CPU,即多核服务器;模拟出来的是在一个CPU的情况下,在同一个时间点只执行一个代码,由于切换快,就造成了多线程的错觉。

  1. main和gc
  • main是用户线程,也是程序执行的主线程
  • gc是守护线程,垃圾回收
  • JVM会在所有的非守护线程(用户线程)执行完毕后退出;main不是最后一个退出的线程,所以main结束,jvm不一定结束
  • 线程开启不会立即执行,由CPU调度
  1. 多线程实现
  • 继承Thread:不建议
  • 实现Runnable:需new一个Thread类去start
public class TestThread implements Runnable

TestThread testThread = new TestThread();

new Thread(testThread).start();
  • 实现Callable:有返回值和能抛出异常
  1. Thread底层是静态代理实现的
  • 真实对象和代理对象都要实现同一个接口
  • 代理对象要代理真实对象
  • 好处:可以做真实对象做不了的事,真实对象专注做自己的事情
public class StaticProxy {
    public static void main(String[] args) {
        new Thread(()-> System.out.println("结婚了")).start();//静态代理
        new WeddingCompany(new You()).marry();
//        WeddingCompany company = new WeddingCompany(new You());
//        company.marry();
    }
}

interface Marry{
    void marry();
}

class You implements Marry{

    @Override
    public void marry() {
        System.out.println("结婚了");
    }
}

class WeddingCompany implements Marry{

    private Marry target;

    public WeddingCompany(Marry target) {
        this.target = target;
    }

    @Override
    public void marry() {
        before();
        this.target.marry();
        after();
    }

    private void after() {
        System.out.println("收彩礼");
    }

    private void before() {
        System.out.println("布置现场");
    }
}
  1. 线程停止
  • 不推荐使用stop,destroy()方法,已废弃
  • 推荐自己停下来,或建立一个标志位,当flag=false,线程停止
public class TestStop implements Runnable {
    private boolean flag = true;
    @Override
    public void run() {
        while (flag){
            System.out.println("Thread--->Run");
        }
    }
    public void stop(){
        this.flag = false;
    }

    public static void main(String[] args) {
        TestStop testStop = new TestStop();
        new Thread(testStop).start();
        for (int i = 0; i < 10; i++) {
            if(i == 9){
                testStop.stop();
            }
        }
    }
}
  1. 线程休眠
  • 每个对象都有一把锁,sleep方法不会释放锁,wait会释放锁
  • sleep模拟网络延迟,方法并发问题的发生性
  1. 线程礼让 yield
  • 让线程从运行态转成就绪态(start),让CPU重新调度线程线程,不一定成功
  1. 线程的状态
  • 创建、就绪、运行、阻塞、死亡(死亡的线程就不能启动了)
  1. 优先级
  • 优先级低只是意味着获得CPU调度的概率低
  1. 线程同步
  • 加入锁机制synchronized,可能会引起性能倒置(高优先级的等待低优先级的释放锁,效率),比如上厕所,不是很急的先上,后面有个很急的等待
  • synchronized:一般只同步修改操作,查询不用,默认同步this本身
    同步需要同步修改的对象(增删改),查询不需要
//同步块,需在线程类内使用
synchronized(被修改的对象){
    //具体代码
}
  1. 死锁
  • 两个线程抢一个唯一资源(一个同步块拥有两个对象锁)
if (choice == 0){
    synchronized (lipStick){
        System.out.println(this.girlName+"获得口红");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        synchronized (mirror){
            System.out.println(this.girlName+"获得镜子");
        }
    }
}else {
    synchronized (mirror){
        System.out.println(this.girlName+"获得镜子");
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        synchronized (lipStick){
            System.out.println(this.girlName+"获得口红");
        }
    }
}
//将里面的同步块拿出来就好了,不要让一个代码块获取两个对象锁
  • 死锁的条件
    • 互斥:一个资源一次只能一个线程使用
    • 请求与保持:一个进程因请求资源阻塞,对已有的资源保持不放
    • 不可剥夺:进程获得的资源,在使用完之前,不能被剥夺
    • 循环等待:若干进程形成头尾相接的循环等待关系
  1. Lock
  • 锁提供了对共享资源的独占访问,每次只能一个线程对Lock对象加锁
  • 一般使用ReentrantLock(可重入锁)
try {
    lock.lock();//加锁
    if(num >= 0){
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(num--);
    }else{
        break;
    }
} finally {
    lock.unlock();//解锁
}

synchronized和lock的区别:

  • lock是显式锁、synchronized是隐式,出了作用域自动释放
  • lock只能锁代码块,s…方法也可
  • lock锁,jvm花费时间少,性能好
  • 优先使用顺序:Lock>同步代码块>同步方法
  1. 生产者消费者模式
  • 使用synchronized同步,wait和notify/notifyAll实现线程通信(wait会让出对象锁,sleep不会),相当于wait在syn代码块中不需要执行完才让出对象锁
  • 但notify只是唤醒wait的线程,但是不会释放对象锁,需要等当前syn执行完才会释放,另一个wait的线程才会进入等待状态,等待CPU调度
  1. 线程池
  • 提前创建多个线程,使用时在池中获取,使用完放回,避免频繁创建销毁造成的性能开销,实现重复利用,提高性能
  • 好处:提高响应速度,降低资源消耗,便于线程管理

四、注解和反射

  1. 内置注解
  • @Deprecated:表示不鼓励程序员用这样的元素,如废弃方法
  • @SupperessWarnings:抑制编译器错误信息,镇压警告
  1. 元注解(meta-annotation):解释其他注解的注解
  • @Target:描述使用范围,方法上还是类上
  • @Retention:表示在什么地方注解还有效,源代码,编译,运行时(SOURCE<CLASS<RUNTIME(一般用))
  • @Document:将注解生成到JavaDoc中
  • @Inherited:子类可以继承父类的注解
public class TestAnnotation {

    @MyAnnotation(age = 1)
    public void test(){

    }
}

@Target({ElementType.METHOD,ElementType.TYPE}) //可在哪使用
@Retention(RetentionPolicy.RUNTIME) //定义在什么生命周期生效
@interface MyAnnotation{
    //参数:类型+名字 +() + 可选(default n 默认值)
    String name() default "";
    int age();
    String[] sName() default {"成信大","川大"};
}
  1. 反射
  • 正常:引入包名->new 实例化->取得实例对象
  • 反射:实例化对象->getClass()方法->得到完整的包名
Class c1 = Class.forName("com.lvboaa.User");
  • 一个Class对象加载到JVM中只会有一个

类加载的过程:

  • 加载:将class文件通过javac编译加载到内存中,将静态数据转化成方法区的运行时数据,生成一个class对象
  • 链接:将二进制代码合并到JVM Java的运行环境中
    • 验证:确保类信息符合JVM规范,没有安全问题
    • 准备:为类变量(static)分配内存赋初始值,并将之放入常量池
    • 解析:将引用类型替换成真实的地址
  • 初始化
    • 执行类构造器方法,合并静态代码块(包括块和变量),合并的时候跟静态变量和代码块的前后顺序有关
    • 初始化一个类,如果发现父类没初始化,就先初始化父类
    • 虚拟机保证方法在多线程安全(同步)

调用类的常量和静态变量、新建对象数组不会对类进行初始化

  1. 反射创建对象
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException,
    InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
    //获取Class对象
    Class c1 = Class.forName("com.lvboaa.test1.User");
    User user = (User) c1.newInstance(); //创建对象,本质是调用了无参构造
    System.out.println(user);
    //通过构造器创建
    //参数需要和用什么构造器创建对象的参数一致
    Constructor constructor=c1.getDeclaredConstructor(int.class,String.class);
    User user1 = (User) constructor.newInstance(1,"lvbo");//设置参数
    System.out.println(user1);

    //通过反射调用普通方法
    User user2 = (User)c1.newInstance();
    Method method =c1.getDeclaredMethod("setName",String.class);
    method.invoke(user2,"lvbo");
    System.out.println(user2);

    //通过反射访问属性
    User user3 = (User)c1.newInstance();
    Field name = c1.getDeclaredField("name");
    name.setAccessible(true);//设置安全检查关闭,就可访问私有属性
    name.set(user3,"lvbo");
    System.out.println(user3);
}

反射就是在运行时才知道要操作的类是什么,并且可以在运行时获取类的完整构造,并调用对应的方法。
效率问题:直接new对象调用方法速度最快,反射慢了几百倍,关闭检测也比普通反射效率快了三倍左右,所以需要经常调用反射一般关闭检测(不允许访问private修饰的…)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值