Java基础复习笔记(附黑马学习视频地址)

Java基础视频

Java的内存需要划分成为5个部分:

1.栈(Stack):存放的都是方法中的局部变量。方法的运行一定要在栈当中运行。

					局部变量:方法的参数,或者是方法{}内部的变量
					作用域:—旦超出作用域,立刻从栈内存当中消失。

2.堆(Heap):凡是new出来的东西,都在堆当中。

					堆内存里面的东西都有一个地址值:16进制
					堆内存里面的数据,都有默认值。规则:
								如果是整数			默认为0
								如果是浮点数		默认为0.0
								如果是字符			默认为 '\u0000'
								如果是布尔			默认为false
								如果是引用类型	默认为null

局部变量在栈内存中(跟着方法走,方法在栈内存中运行),成员变量在堆内存中(new对象的时候里面有成员变量)
3.方法区(Method Area):存储.class相关信息,包含方法的信息。
4.本地方法栈(Native Method Stack):与操作系统相关。
5.寄存器(pc Register): 与CPU相关。

数组的内存图:

数组内存图

一个对象的内存图:

视频地址
在这里插入图片描述

两个对象调用同一个方法的内存图:

视频地址
在这里插入图片描述

两个引用指向同一个对象的内存图:

视频地址
在这里插入图片描述

将数组中的元素进行反转的算法:

public static void main(String[] args) {
	int arr[] = {10, 20, 30, 40, 50};
	for (int min = 0, max = arr.length - 1; min < max; min++, max--) {
	    int temp = arr[min];
	    arr[min] = arr[max];
	    arr[max] = temp;
	}
	for (int i : arr) {
	    System.out.println(i);
	}
}

成员变量和局部变量的区别

  • 定义的位置不同:成员变量(类中方法外)局部变量(方法内部或方法声明上)
  • 作用范围不同:成员变量(整个类全都可以使用)局部变量(只有在方法中可以使用,出了方法就不能再用)
  • 内存中位置不同:成员变量(堆内存)局部变量(栈内存)
  • 生命周期不同:成员变量(随着对象的存在而存在,随着对象的消失而消失)局部变量(随着方法的调用而存在,随着方法的调用完毕而消失)
  • 初始化值不同:成员变量(有默认初始化值)局部变量(没有默认初始化值,必须先定义,赋值才能使用)

访问权限修饰符的区别:

修饰符当前类同包字类其他包
public
protected×
default××
private×××
Java中的数据类型

Java是一个强类型语言,Java中的数据必须明确数据类型。在Java中的数据类型包括基本数据类型和引用数据类型两种。

Java中的基本数据类型:【四类(整型、浮点型、字符型、布尔型)八种】

数据类型关键字内存占用(字节)取值范围
整数byte1-2^7 ~ 2^7-1(-128~127)
short2-2^15 ~ 2^15-1(-32768~32767)
int4-2^31 ~ 2^31-1
long8-2^63 ~ 2^63-1
浮点数float41.401298e-45 ~ 3.402823e+38
double84.9000000e-324 ~ 1.797693e+308
字符char20-65535
布尔boolean1true,false

在这里插入图片描述

字符串相关知识

字符串的特点:
  • 字符串的内容永不可变【重点】
  • 正是因为字将串不可改变,所以字符串是可以共亨使用的
  • 字符串效果上相当子是char[]字符数组,但是底层原理是byte[ ]字节数组。
       String str = "abc";    等效于: 
       char data[] = {'a', 'b', 'c'};  
       String str = new String(data);
StringBuilder(效率高,线程不安全)

StringBuilder在内存中始终是一个数组,占用空间少,效率高。如果超出了StringBuilder的容量,会自动的扩容

  • 字符串缓冲区,可以提高字符串的操作效率(看或一个长度可以变化的字符串)
  • 底层也是—个数组,但是没有被final修饰,可以改变长度
  • byte]value = new byte[16](默认初始化长度为16)
StringBuffer(效率没有StringBuilder高,线程安全)

多态

多态的概述

什么是多态:同一个对象,在不同时刻表现出来的不同形态
多态的前提:要有继承或实现关系 要有方法的重写 要有父类引用指向子类对象

多态中的成员访问特点

成员访问特点

  • 成员变量 编译看父类,运行看父类
  • 成员方法 编译看父类,运行看子类
多态的好处和弊端
  • 好处 :提高程序的扩展性。定义方法时候,使用父类型作为参数,在使用的时候,使用具体的子类型参与操作
  • 弊端:不能使用子类的特有成员

内部类

  • 内部类概念
    • 在一个类中定义一个类。举例:在一个类A的内部定义一个类B,类B就被称为内部类
  • 内部类定义格式
    • 格式&举例:
 /*
	格式:
    class 外部类名{
    	修饰符 class 内部类名{
    	
    	}
    }
*/

class Outer {
    public class Inner {
        
    }
}
  • 内部类的访问特点
    • 内部类可以直接访问外部类的成员,包括私有
    • 外部类要访问内部类的成员,必须创建对象
  • 示例代码:
/*
    内部类访问特点:
        内部类可以直接访问外部类的成员,包括私有
        外部类要访问内部类的成员,必须创建对象
 */
public class Outer {
    private int num = 10;
    public class Inner {
        public void show() {
            System.out.println(num);
        }
    }
    public void method() {
        Inner i = new Inner();
        i.show();
    }
}
成员内部类
  • 成员内部类的定义位置
    • 在类中方法,跟成员变量是一个位置
  • 外界创建成员内部类格式
    • 格式:外部类名.内部类名 对象名 = 外部类对象.内部类对象;
    • 举例:Outer.Inner oi = new Outer().new Inner();
  • 成员内部类的推荐使用方案
    • 将一个类,设计为内部类的目的,大多数都是不想让外界去访问,所以内部类的定义应该私有化,私有化之后,再提供一个可以让外界调用的方法,方法内部创建内部类对象并调用。
  • 示例代码:
class Outer {
    private int num = 10;
    private class Inner {
        public void show() {
            System.out.println(num);
        }
    }
    public void method() {
        Inner i = new Inner();
        i.show();
    }
}
public class InnerDemo {
    public static void main(String[] args) {
		//Outer.Inner oi = new Outer().new Inner();
		//oi.show();
        Outer o = new Outer();
        o.method();
    }
}
public class InnerClass {
    private int num = 10;
    public class Inner {
        int num = 20;
        public void method() {
            int num = 30;
            System.out.println(num);//局部变量num
            System.out.println(this.num);//内部类num
            System.out.println(InnerClass.this.num); //外部类num
        }
    }
}
局部内部类

注意

  • 局部内部类不能使用修饰符:public、private、(default)、protected
  • 局部内部类如果希望访问所在方法的局部变量,那么这个变量必须是final修饰的

  • 局部内部类定义位置
    • 局部内部类是在方法中定义的类
  • 局部内部类方式方式
    • 局部内部类,外界是无法直接使用,需要在方法内部创建对象并使用
    • 该类可以直接访问外部类的成员,也可以访问方法内的局部变量
  • 示例代码
class Outer {
    private int num = 10;
    public void method() {
        int num2 = 20;
        class Inner {
            public void show() {
                System.out.println(num);
                System.out.println(num2);
            }
        }
        Inner i = new Inner();
        i.show();
    }
}
public class OuterDemo {
    public static void main(String[] args) {
        Outer o = new Outer();
        o.method();
    }
}
匿名内部类
  • 匿名内部类的前提

    • 存在一个类或者接口,这里的类可以是具体类也可以是抽象类
  • 匿名内部类的格式

    • new 类名 ( ) { 重写方法 }

    • new 接口名 ( ) { 重写方法 }

    • 举例:

      new Inter(){
          @Override
          public void method(){}
      } 
      
  • 匿名内部类的本质

    • 本质:是一个继承了该类或者实现了该接口的子类匿名对象
  • 匿名内部类的细节

    • 匿名内部类可以通过多态的形式接受

      Inter i = new Inter(){
        @Override
          public void method(){
              
          }
      }
      
  • 匿名内部类直接调用方法

    interface Inter{
        void method();
    }
    
    class Test{
        public static void main(String[] args){
            new Inter(){
                @Override
                public void method(){
                    System.out.println("我是匿名内部类");
                }
            }.method();	// 直接调用方法
        }
    }
    

数据结构

Collection

单列集合的体系结构

在这里插入图片描述

迭代器Iterator:在使用过程中不能对元素进行添加

Set集合不能存储相同元素的原因

在这里插入图片描述

Comparab接口

在使用Collections的sort方法时,集合中的对象类型需要实现Comparable接口并重写CompartTo方法。
个人猜测原理:在CompareTo的返回值结果中,如果为负,则交换位置;如果相等或为正,位置不变。

多列集合的体系结构

泛型

泛型类
  • 定义格式

    修饰符 class 类名<类型> {  }
    
  • 示例代码

    • 泛型类

      public class Generic<T> {
          private T t;
      
          public T getT() {
              return t;
          }
      
          public void setT(T t) {
              this.t = t;
          }
      }
      
泛型方法
  • 定义格式

    修饰符 <类型> 返回值类型 方法名(类型 变量名) {  }
    
  • 示例代码

    • 带有泛型方法的类

      public class Generic {
          public <T> void show(T t) {
              System.out.println(t);
          }
      }
      
泛型接口
  • 定义格式

    修饰符 interface 接口名<类型> {  }
    
  • 示例代码

    • 泛型接口

      public interface Generic<T> {
          void show(T t);
      }
      
    • 泛型接口实现类

      public class GenericImpl<T> implements Generic<T> {
          @Override
          public void show(T t) {
              System.out.println(t);
          }
      }
      

类型通配符【应用】

可变参数

  • 可变参数介绍

    ​ 可变参数又称参数个数可变,用作方法的形参出现,那么方法参数个数就是可变的了

  • 可变参数定义格式

    修饰符 返回值类型 方法名(数据类型...   变量名) {  }
    public void method(int... num)
      public void method(int a, int... num)
    
  • 可变参数的注意事项

    • 这里的变量其实是一个数组
    • 如果一个方法有多个参数,包含可变参数,可变参数要放在最后

枚举

枚举中带构造函数的定义
public enum EnumDemo {
    //必须放在第一行 调用下面的构造方法,中间以逗号隔开,末尾分号
    SPRING("春天", 1), SUMMER(""), AUTUMN(""), WINTER();

    private String name;
    private int index;

    EnumDemo() {
    }

    EnumDemo(String name) {
        this.name = name;
    }

    EnumDemo(int index) {
        this.index = index;
    }

    EnumDemo(String name, int index) {
        this.name = name;
        this.index = index;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getIndex() {
        return index;
    }

    public void setIndex(int index) {
        this.index = index;
    }

}

多线程

解决多线程数据安全的问题
1.使用synchronized同步代码块

synchronized(任意对象) { 多条语句操作共享数据的代码 }

  • 同步的好处和弊端

    • 好处:解决了多线程的数据安全问题
    • 弊端:当线程很多时,因为每个线程都会去判断同步上的锁,这是很耗费资源的,无形中会降低程序的运行效率
  • 代码演示

    public class SellTicket implements Runnable {
        private int tickets = 100;
        private Object obj = new Object();
    
        @Override
        public void run() {
            while (true) {
                //tickets = 100;
                //t1,t2,t3
                //假设t1抢到了CPU的执行权
                //假设t2抢到了CPU的执行权
                synchronized (obj) {
                    //t1进来后,就会把这段代码给锁起来
                    if (tickets > 0) {
                        try {
                            Thread.sleep(100);
                            //t1休息100毫秒
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        //窗口1正在出售第100张票
                        System.out.println(Thread.currentThread().getName() + "正在出售第" + tickets + "张票");
                        tickets--; //tickets = 99;
                    }
                }
                //t1出来了,这段代码的锁就被释放了
            }
        }
    }
    
    public class SellTicketDemo {
        public static void main(String[] args) {
            SellTicket st = new SellTicket();
    
            Thread t1 = new Thread(st, "窗口1");
            Thread t2 = new Thread(st, "窗口2");
            Thread t3 = new Thread(st, "窗口3");
    
            t1.start();
            t2.start();
            t3.start();
        }
    }
    
2.使用同步方法
  • 同步方法的格式

    同步方法:就是把synchronized关键字加到方法上

    修饰符 synchronized 返回值类型 方法名(方法参数) { 
    	方法体;
    }
    

    同步方法的锁对象是什么呢?

    ​ this

  • 静态同步方法

    同步静态方法:就是把synchronized关键字加到静态方法上

    修饰符 static synchronized 返回值类型 方法名(方法参数) { 
    	方法体;
    }
    

    同步静态方法的锁对象是什么呢?

    ​ 类名.class

  • 代码演示

    public class SellTicket implements Runnable {
        private static int tickets = 100;
        private int x = 0;
    
        @Override
        public void run() {
            while (true) {
    			sellTicket()}
        }
    //    同步方法
    //    private synchronized void sellTicket() {
    //        if (tickets > 0) {
    //            try {
    //                Thread.sleep(100);
    //            } catch (InterruptedException e) {
    //                e.printStackTrace();
    //            }
    //            System.out.println(Thread.currentThread().getName() + "正在出售第" + tickets + "张票");
    //            tickets--;
    //        }
    //    }
        
    //  静态同步方法
        private static synchronized void sellTicket() {
            if (tickets > 0) {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "正在出售第" + tickets + "张票");
                tickets--;
            }
        }
    }
    
    public class SellTicketDemo {
        public static void main(String[] args) {
            SellTicket st = new SellTicket();
    
            Thread t1 = new Thread(st, "窗口1");
            Thread t2 = new Thread(st, "窗口2");
            Thread t3 = new Thread(st, "窗口3");
    
            t1.start();
            t2.start();
            t3.start();
        }
    }
    
3.使用Lock锁

虽然我们可以理解同步代码块和同步方法的锁对象问题,但是我们并没有直接看到在哪里加上了锁,在哪里释放了锁,为了更清晰的表达如何加锁和释放锁,JDK5以后提供了一个新的锁对象Lock

Lock是接口不能直接实例化,这里采用它的实现类ReentrantLock来实例化

  • ReentrantLock构造方法

    方法名说明
    ReentrantLock()创建一个ReentrantLock的实例
  • 加锁解锁方法

    方法名说明
    void lock()获得锁
    void unlock()释放锁
  • 代码演示

    public class SellTicket implements Runnable {
        private int tickets = 100;
        private Lock lock = new ReentrantLock();
    
        @Override
        public void run() {
            while (true) {
                try {
                    lock.lock();
                    if (tickets > 0) {
                        try {
                            Thread.sleep(100);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println(Thread.currentThread().getName() + "正在出售第" + tickets + "张票");
                        tickets--;
                    }
                } finally {
                    lock.unlock();
                }
            }
        }
    }
    public class SellTicketDemo {
        public static void main(String[] args) {
            SellTicket st = new SellTicket();
    
            Thread t1 = new Thread(st, "窗口1");
            Thread t2 = new Thread(st, "窗口2");
            Thread t3 = new Thread(st, "窗口3");
    
            t1.start();
            t2.start();
            t3.start();
        }
    }
    
线程池

其实就是一个容纳多个线程的容器,其中的线程可以反复使用,省去了频繁创建线程对象的操作,无需反复创建线程而消耗过多资源。

Java里面线程池的顶级接口是java.util.concurrent.Executor,但是严格意义上讲Executor并不是一个线程池,而只是一个执行线程的工具。真正的线程池接口是java.util.concurrent.ExecutorService

要配置一个线程池是比较复杂的,尤其是对于线程池的原理不是很清楚的情况下,很有可能配置的线程池不是较优的,因此在java.util.concurrent.Executors线程工厂类里面提供了一些静态工厂,生成一些常用的线程池。官方建议使用Executors工程类来创建线程池对象。

Executors类中有个创建线程池的方法如下:

  • public static ExecutorService newFixedThreadPool(int nThreads):返回线程池对象。(创建的是有界线程池,也就是池中的线程个数可以指定最大数量)

获取到了一个线程池ExecutorService 对象,那么怎么使用呢,在这里定义了一个使用线程池对象的方法如下:

  • public Future<?> submit(Runnable task):获取线程池中的某一个线程对象,并执行

    Future接口:用来记录线程任务执行完毕后产生的结果。线程池创建与使用。

使用线程池中线程对象的步骤:

  1. 创建线程池对象。
  2. 创建Runnable接口子类对象。(task)
  3. 提交Runnable接口子类对象。(take task)
  4. 关闭线程池(一般不做)。

Runnable实现类代码:

public class MyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println("我要一个教练");
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("教练来了: " + Thread.currentThread().getName());
        System.out.println("教我游泳,交完后,教练回到了游泳池");
    }
}

线程池测试类:

public class ThreadPoolDemo {
    public static void main(String[] args) {
        // 创建线程池对象
        ExecutorService service = Executors.newFixedThreadPool(2);//包含2个线程对象
        // 创建Runnable实例对象
        MyRunnable r = new MyRunnable();

        //自己创建线程对象的方式
        // Thread t = new Thread(r);
        // t.start(); ---> 调用MyRunnable中的run()

        // 从线程池中获取线程对象,然后调用MyRunnable中的run()
        service.submit(r);
        // 再获取个线程对象,调用MyRunnable中的run()
        service.submit(r);
        service.submit(r);
        // 注意:submit方法调用结束后,程序并不终止,是因为线程池控制了线程的关闭。
        // 将使用完的线程又归还到了线程池中
        // 关闭线程池
        //service.shutdown();
    }
}

File

绝对路径和相对路径
  • 绝对路径:从盘符开始的路径,这是一个完整的路径。
  • 相对路径:相对于项目目录的路径,这是一个便捷的路径,开发中经常使用。
递归原理

在这里插入图片描述

IO流

IO的分类

根据数据的流向分为:输入流输出流
在这里插入图片描述

  • 输入流 :把数据从其他设备上读取到内存中的流。
  • 输出流 :把数据从内存 中写出到其他设备上的流。

格局数据的类型分为:字节流字符流

  • 字节流 :以字节为单位,读写数据的流。
  • 字符流 :以字符为单位,读写数据的流。
IO的流流向说明图解

在这里插入图片描述

顶级父类们
输入流输出流
字节流字节输入流
InputStream
字节输出流
OutputStream
字符流字符输入流
Reader
字符输出流
Writer
IO流类的关系
字节流
字节输入流字节输出流
Father输入流
InputStream
字节输出流
OutputStream
Son输入流
FileInputStream
输出流
FileOutputStream
字符流
字符输入流字符输出流
Father输入流
Reader
输出流
Writer
Son输入流
InputStreamReader
输出流
OutputStreamWriter
Son-Son输入流
FileReader
输出流
FileWriter

反射

Java代码的三个阶段:
在这里插入图片描述

  • 框架:半成品软件。可以在框架的基础上进行软件开发,简化编码
  • 反射:将类的各个组成部分封装为其他对象,这就是反射机制
    • 好处:
      1. 可以在程序运行过程中,操作这些对象。
      2. 可以解耦,提高程序的可扩展性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值