Java笔记

注解

1、注解,或者叫注释,英文:Annotation
2、注解Annotation是一种引用数据类型,编译之后生成xxx.class文件
3、如何自定义注解?语法格式?
    [修饰符列表] @interface 注解类型名{
    }
    例如:public @interface AnnotationToken{
		  }
4、注解怎么使用,用在什么地方?
    1、注解使用时的语法格式是:
        @注解类型名
    2、注解可以出现在类上,属性上,方法上,变量上等
        注解还可以出现在注解类型上
        默认情况下可以出现在任意位置
5、JDK内置了哪些注解
    java.lang包下的注释类型:
        掌握:
        Deprecated 用@Deprecated注释的程序元素,表示已过时
        不鼓励程序员使用这样的元素,通常是因为它很危险或存在更好的选择
        掌握:
        Override表示一个方法生命打算重写超类中的另一个方法声明
        Override只能注解方法,是给编译器参考的,和运行阶段无关
        如果这个方法不是重写父类的方法,编译器报错
        不用掌握:
        SuppressWarnings指示应该在注释元素(以及包含在改注释元素中的所有程序元素)
        中取消显示指定的编译器警告
6、元注解
    用来标注“注解类型”的“注解”,称为元注解
    常见的元注解:
        Target
        Retention
    关于Target注解:
        这是一个元注解,用来标注“注解类型”的“注解”
        这个Target注解用来标注“被标注的注解”可以出现在那些位置上。

        @Target(ElementType.METHOD):表示”被标注的注解“只能出现在方法上
        @Target({ElementType.TYPE, ElementType.METHOD}):表示注解可以标注在 类 和 方法 上。
    关于Retention注解:
        这也是一个元注解
        这个Retention注解用来标注”被标注的注解“最终保存在哪里

        @Retention(RetentionPolicy.SOURCE):表示该注解只被保留在java源文件中
        @Retention(RetentionPolicy.CLASS):表示该注解只被保留在class文件中
        @Retention(RetentionPolicy.RUNTIME):表示该注解只被保留在class文件中,并且可以被反射机制所读取

7、自定义注解
    注解当中的属性可以是以下任意一种类型
        byte short int long float double boolean char String Class 枚举类型
        以及每一种的数组形式

	自定义注解中定义属性:
	public @interface MyAnnotation {
	    /**
	     * 我们通常在注解当中可以定义属性,以下这个是MyAnnotation的name属性
	     * 看着像一个方法,但实际上我们称之为属性name
	     */
	    String name();
	    String color();
		String[] email();
	    int age() default 25;   //给定默认值,这样就不用使用注解时再赋值
	
	}
	***如果一个注解当中有属性,那么使用注解时必须给属性赋值,给定过默认值的除外。
	例如: @MyAnnotation(name = "芜湖", color = "Red". email = {"WDNMD", "起飞"})
 	赋值时,如果注解属性数组(如:上面的email)只有一个值,大括号可以省略(如:email = "WDNMD")

	如果一个注解的属性名为value,并且仅有这一个属性,那么在使用注解给属性赋值时,属性名value可以不写
	如:public @interface ValueAnnotation {
		    String value();
		}
	使用注解时,可以将@ValueAnnotation(value = "WDNMD")
	简写为:@ValueAnnotation("WDNMD")

数组

1、 Java语言中的数组是一种引用数据类型,数组的父类也是Object
2、 数组实际上是一个容器,可以容纳多个元素
3、 可以存储基本数据类型的数据,也可以存储引用数据类型的数据
4、 由于数据是引用数据类型,数组对象也是在堆内存当中
5、 数组当中如果存储的是Java对象的话,实际上存储的是对象的引用,即:内存地址
6、 数组一旦创建,长度不可变
7、 数组分类:一维,二维,三维,多维。。。(一维较多,二维偶尔使用)
8、 数组对象自带Length属性,用来获取数组长度
9、 数组中的元素内存地址是连续的,引用存放的地址是数组首元素的地址
10、 数组的优缺点:
        优点:   查询/查找/检索某个下标上的元素时效率极高,可以说是查询效率最高的一个数据结构
                为什么效率高?
                    一、每一个元素的内存地址在空间存储上是连续的
                    二、每一个数据元素的类型相同,所以占用空间大小一样
                    三、知道第一个元素的内存地址,知道每一个元素占用空间的大小,又知道下标,
                        所以通过一个数学表达式就可以计算出某个下标上元素的内存地址。直接通过内存地址
                        定位元素,所以数组的检索效率是最高的。
                数组中存储100个元素,或100万个元素,查找效率是相同的,
                因为数组中元素查找的时候不会一个一个找,是通过数学表达式计算出来的。(算出一个
                内存地址,直接定位的。)

        缺点:   1、为了保持数组中每个元素的内存地址连续,增加或删除元素使需要移动其他元素(除最后一个元素)
                2、数组不能存储大数据量,因为很难在内存空间中找到一块特别大的连续的内存空间。
11、 定义一个一维数组的语法格式:
        数据类型[] 变量名;
12、 如何初始化一个一维数组
        两种方式:
                静态初始化语法格式:
                        数据类型[] 变量名 = {a, b, c, d};
                动态初始化语法格式:
                        数据类型[] 变量名 = new 数据类型[length];  元素默认值为0或null
13、 当确定数组中存放的具体数据时采用静态初始化,否则采用动态初始化预分配空间。
14、 各数据类型的默认值
        byte            0
        short           0
        int             0
        long            0L
        float           0.0F
        double          0.0
        boolean         false
        char            \u0000
        引用             null
15、数组扩容:
	先创建一个大容量数组,再将小容量数组中的数据一个一个拷贝到大数组中
数组扩容效率很低,尽量一开始就将数组容量设计合适

Java中的数组如何拷贝:
                          拷贝源      源起始下标      拷贝目标    目标起始下标    长度
    System.arraycopy(Object src,  int  srcPos, Object dest, int destPos, int length);
    拷贝源:从哪个数组拷贝
    拷贝目标:拷贝到哪个数组
    例如:将数组 a1 从下标为 1 的位置开始拷贝到数组 a2 从下标为 3 的位置开始,拷贝长度为2
    System.arraycopy(a1, 1, a2, 3, 2);
16、数组工具类
	Java 中已经封装好了排序算法,可直接调用
	Java 中提供了一个数组工具类: java.util.Arrays
    Arrays是一个工具类,其中有一个 static 的 sort() 方法,可直接使用Arrays.sort()
    所有方法都是静态的
    常用的有两个:二分法查找 binarySearch(),排序 sort()

集合

1、什么是集合?有什么用?
集合实际上就是一个容器,可以来容纳其他类型的数据,集合是一个载体,可以一次容纳多个对象,在开发中使用较多
2、集合不能直接存储基本数据类型,另外集合也不能直接存储java对象,存储的都是java对象的内存地址(引用)
    list.add(10);   自动装箱Integer
    集合在java中本身是一个容器,一个对象
    集合中任何时候存储的都是“引用”
3、在java中每一个不同的集合,底层会对应不同的数据结构。往不同的集合中存储元素,等于数据放到了不同的数据结构中。
    数据结构有:数组,二叉树,链表,哈希表等
4、所有的集合类和集合接口都在java.util包下
5、java中集合分为两大类
    一类是单个方式存储元素
        单个方式存储元素,这一类集合中超级父接口:java.util.Collection;
    一类是以键值对儿的方式存储元素
        以键值对的方式存储元素,这一类集合中超级父接口:java.util.Map;
6、java.util.Collection接口中常用的方法
    1)、Collection中存放的元素
        没有使用泛型之前,Collection中可以存储Object的所有子类型
        使用了泛型之后,只能存储某个具体的类型
    2)、Collection中常用的方法
        boolean add(Object e)   向集合中添加元素
        int size()  获取集合中的元素个数
        void clear() 清空集合
        boolean contains(Object o) 判断当前集合中是否包含元素o,包含返回true,反之false
        boolean remove(Object o)  删除集合中某个元素
        boolean isEmpty();  判断集合中的元素个数是否为0
        Object[] toArray()  将集合转换成数组
        
7、ArrayList
	ArrayList集合初始化容量是10(底层先创建了一个长度为0的数组,当添加第一个元素的时候,初始化容量10)
	底层是Object类型的数组
	ArrayList集合的扩容:
	    原容量的1.5倍
	    由于底层是数组,尽量避免扩容,初始化时尽量选择适当的容量避免扩容
    默认初始化容量是10,但也可以通过构造方法指定初始化容量,例如:new ArrayList(20);

8、HashMap集合:
    1)、HashMap集合底层是哈希表
    2)、哈希表是一个数组和单向链表的结合体,充分发挥他们各自的优点
    3)、同一个链表上所有结点的hash相同,因为它们的数组下标是一样的
    4)、任何一个链表上k和k的equals方法肯定返回的是false
    5)、HashMap集合的默认初始化容量是16,默认加载因子是0.75
        默认加载因子是当HashMap集合底层数组的容量达到75%时,数组开始扩容
        HashMap集合初始化容量必须是2的倍数,官方推荐的,这是因为达到散列均匀,为了提高HashMap集合的存取效率,所必须的
    6)、扩容是原来的2倍
    
	7)、map.put(k, v)实现原理:
	    (1)、先将k,v封装到Node对象中
	    (2)、底层会调用k的hashCode()方法得出hash值,
	       然后通过哈希算法,将hash值转换成数组的下标,下标位置上如果没有任何元素,
	       就把Node添加到该位置,如果下标对应位置上有链表,此时会用k和链表上每一个结点的k
	       进行equals,如果所有的equals都返回false,就把改结点插入到链表的尾端,如果
	       其中又一个equals返回了true,这个结点的value就会被覆盖。
	8)、map.get(k)实现原理:
        先调用k的hashCode方法得出哈希值,通过哈希算法转换成数组下标,通过数组下标快速
    定位到某个位置上,如果这个位置什么也没有,返回null。如果有链表,那么使用k和链表上
    每个结点的k进行equals,如果所有equals都返回false,则get方法返回null,只要其中
    有一个equals返回true,那么get方法返回这个结点的value。
    
    9)、equals 和 hashCode方法
	    如果一个类的equals方法重写了,hashCode方法必须重写,
    且equals方法返回true时,hashCode方法的返回值必须一样,
    因为equals返回true表示两个对象相同,是在同一个单向链表上比较的,
    而同一个单向链表上的所有结点的哈希值都相同,故hashCode的返回值必须一样

    放在HashMap集合key部分的,以及HashSet集合中的元素需要同时重写equals和hashCode方法

9、List接口常用方法
    List集合存储元素特点:有序可重复
        有序:集合中元素有下标
        可重复:可以存储相同的元素
    List集合特有的方法(除了父接口Collection中继承的方法):
        常用的:
            void add(int index, Object element)
            Object get(int index)
            int LastIndexOf(Object o)
            Object remove(int index)
            Object set(int index, Object element)
10、Map接口常用方法
	    Map集合以key和value的方式存储数据
	    key和value都是引用数据类型
	    -------------------------------
	    V put(K key, V value)   向Map集合中添加键值对
	    V get(Object key)       通过key获取value
	    void clear()            清空Map集合
	    boolean containsKey(Object key) 判断Map中是否包含某个key
	    boolean containsValue(Object value) 判断Map中是否包含某个value
	    boolean isEmpty()       判断Map集合中所有元素个数是否为0
	    Set<K> keySet()         获取Map集合所有的key
	
	    V remove(Object key)    通过key删除键值对
	    int size()              获取键值对的个数
	    Collection<V> values()  获取Map集合中所有的value,返回一个Collection
	    Set<Map.Entry<K, V>> entrySet() 将Map集合转换成Set集合
11、Properties
	Properties是一个Map集合,继承Hashtable,Properties的key和value都是String类型
	Properties被称为属性类对象,是线程安全的
	
	要掌握两个方法,一个存,一个取
		Properties pro = new Properties();
		添加元素:pro.setProperty("key", "value");	
    	获取元素:pro.getProperty("key");
12/、Vector:
	    底层也是数组
	    初始容量10
	    扩容之后是原来容量的2倍
	    所有方法都是线程同步的,都带有synchronized关键字,效率较低,使用较少
	    怎么将一个线程不安全的ArrayList集合转换成线程安全的: 使用集合工具类
	        java.util.Collections   是集合工具类
	        java.util.Collection    是集合接口

StringBuffer和StringBuilder的区别

StringBuffer中的方法都有:synchronized关键字修饰,表示StringBuffer在多线程环境下运行是安全的
StringBuilder中的方法都没有:synchronized关键字修饰,表示StringBuilder在多线程环境下运行是不安全的
如果使用的只有局部变量,建议使用StringBuilder,因为局部变量必不共享,不需要考虑线程安全问题,
若使用StringBuffer,由于是线程安全的,会导致效率降低

线程

多线程概述:
    1、什么是进程?什么是线程?
        进程是一个应用程序
        线程是一个进程中的执行场景/执行单元
        一个进程可以启动多个线程
    2、对于java程序来说,当在DOS命令窗口中输入;
        java HelloWorld回车之后,
        会先启动一个主线程调用main方法。
        同时在启动一个垃圾回收线程负责看护,回收垃圾。
        最起码,现在的java程序中至少有两个线程并发,
        一个是垃圾回收线程,一个是执行main方法的主线程
    3、进程A和进程B的内存独立不共享
        线程A和线程B,在java语言中:线程A和线程B:堆内存和方法去内存共享,但是堆内存独立,一个线程一个栈
    4、实现线程的两种方式
        第一:编写一个类,继承java.lang.Thread,重写run方法
        第二:编写一个类,实现java.lang.Runnable接口
了解内容
线程的调度:
    1、常见的线程调度有两种
        抢占式调度模型:
            哪个线程的优先级比较高,抢到的时间片的概率就高一些
            java采用的就是抢占式调度模型
        均分式调度模型:
            平均分配CPU时间片,每个线程占有的CPU时间片时间长度一样
            平均分配,一切平等
    2、java中提供了一些和线程调度有关的方法
        实例方法:
            void setPriority(int new Priority)  设置线程的优先级
            int getPriority()   获取线程优先级
            最低优先级1
            默认优先级5
            最高优先级10
            优先级比较高的获取CPU时间片可能会多一些(但也不完全是)
            void join()     合并线程
                class MyThread1 extends Thread {
                    public void doSome() {
                        MyThrad2 t = new MyThread2();
                        t.join();   //当前线程进入阻塞,t线程执行,直到t线程结束,当前线程才可以继续
                    }
                }

                class MyThread2 extend Thread {
                }
        静态方法:
            static void yield() 让位方法
            暂停当前正在执行的线程对象,并执行其他线程
            yield()方法不是阻塞方法,让当前线程让位,让给其他线程使用
            yield()方法的执行会让当前线程从”运行状态“回到”就绪状态“

重点:关于多线程并发环境下,数据的安全问题
    1、为什么这个是重点
        以后在开发中,我们的项目都是运行在服务器当中,而服务器已经将线程的定义,线程对象的创建,线程的启动等,都已经实现了。不需要我们编写
        最重要的是:你要知道,你编写的程序需要放到一个多线程的环境下运行,你更需要关注的是这些数据在多线程并发的环境下是否是安全的。(重点:*****)
    2、什么时候数据在多线程并发的环境下存在安全问题
        1、多线程并发
        2、有共享数据
        3、共享数据有修改行为
    3、怎么解决线程安全问题
        当多线程并发的环境下,有共享数据,并且这个数据会被修改,此时就存在线程安全问题,如何解决这个问题?
            线程排队执行。(不能并发)
            用排队执行解决线程安全问题
            这种机制被称为:线程同步机制

            专业术语叫:线程同步,实际上就是线程不能并发了,必须排队执行
        线程同步会牺牲一部分效率,没办法,数据安全是第一位
    4、线程同步这块,涉及到两个专业术语
        异步编程模型:
            线程t1和t2,各自执行各自的,谁也不需要等谁,
            其实就是多线程并发(效率较高)
        同步编程模型:
            t1执行时,必须等待t2执行结束,t2执行时,必须等待t1执行结束,两个线程之间发生了等待关系
            效率较低,线程排队执行

            异步就是并发,同步就是排队
    5、Java中有三大变量:
        实例变量:堆中
        静态变量:方法区中
        局部变量:栈中
        以上三大变量中:局部变量永远都不会存在线程安全问题,因为局部变量不共享(一个线程一个栈)
        堆和方法区只有1个,都是多线程共享,所以可能存在线程安全问题
    6、如果使用局部变量的话
        建议使用StringBuilder,因为局部变量不存在线程安全问题,使用StringBuffer的话效率会降低

    7、总结
        synchronized有三种写法
            第一种:同步代码块
                灵活
                synchronized(线程共享对象) {
                    同步代码块;
                }
            第二种:在实例方法上使用synchronized
                表示共享对象一定是this
                并且同步代码块是整个方法体
            第三种:在静态方法上使用synchronized
                表示找类锁
                类锁永远只有1把
                就算常见了100个对象,类锁爷只有一把
            对象锁:1个对象1把锁
            类锁:1个类一把锁
    8、开发中如何解决线程安全问题?
        synchronized会让程序的执行效率降低,在不得以的情况下再使用
        第一种:尽量使用局部变量代替“实例变量和静态变量”
        第二种:如果必须是实例变量,那么可以考虑创建多个对象,这样实例变量的内存就不共享了
        第三种:如果不能使用局部变量,对象也不能创建多个,这个时候就只能选择synchronized,线程同步机制
    9、线程这块其他内容
        1、守护线程
        2、定时器
        3、实现线程的第三种方式:FutureTask方式,实现Callable接口。(JDK8新特性)
        4、关于Object类中的wait和notify方法。(生产者和消费者模式)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值