Java基础记录(六)

此博客为看B老师Java视频的部分记录
  1. 多线程通信生产消费问题
  • 概要:生产者生产商品后告诉消费者,此时生产者应该处于等待状态‘消费者消费了商品后,应告诉生产者,此时消费者处于等待状态
    在这里插入图片描述

  • Condition对象中部分方法:

    • await(): 让线程处于等待状态(将线程临时存储到线程池中)
    • signal(): 唤醒线程池中任意一个等待的线程
    • signalAll(): 唤醒线程池中所有的等待线程
  • 部分示例

	class BoundedBuffer
	{
		final Lock lock = new ReentrantLock(); //锁
		final Condition notFull = lock.newCondition(); //生产
		final Condition notEmpty = lock.newCondition(); //消费
		
		final Object[] items = new Object[100]; //存储商品的容器
		int putptr /*生产者使用的角标*/, takeptr/*消费者使用的角标*/, count/*计数器*/;
		
		//生产者使用的方法,往数组中存储商品
		public void put(Object x) throws InterruptedException
		{
			lock.lock();
			try
			{
				while(count==items.length)// 判断计数器是否已到数组长度(是否已满)
					notFull.await(); //满了则生产者等待
				items[putptr] = x; //按照角标将商品存储在数组中
				if(++putptr == items.length)//如果存储的角标到了数组的长度,就将角标归零
					putptr = 0;
				++count; //计数器自增
				notEmpty.signal();//唤醒一个消费者
			}
			final
			{
				lock.unlock();
			}
		}
		
		public Object take() throws InterruptedException
		{
			lock.lock();
			try
			{
				while(count==0)//如果计数器为0,说明没有商品,消费者等待
					notEmpty.await();
				Object x = items[takeptr];//从数组中通过消费者角标获取商品
				
				if(++takeptr == items.length) //如果消费的角标等于了数组的长度,将角标归零
					takeptr = 0;
				--count; //计数器自减
				notFull.signal(); //唤醒生产者
				return x;
			}
			final
			{
				lock.unlock();
			}
		}
	}

在这里插入图片描述


  1. String类
  • 字符串都是对象
  • 一旦初始化就不可以被更改, 因为是常量
  • 通过String类的构造函数可知,将字节数组或者字符转成字符串
	public class StringDemo {
    public static void main(String[] args) {
        // 定义一个字符串
        String str = "abc";
        System.out.println("str=" + str);

        // ----------------
        System.out.println("--------多个引用指向同一字符串--------");
        String s1 = "itcast";
        String s2 = "itcast";
        System.out.println(s1 == s2);

        System.out.println("--------两个内容相同,创建方式不同的字符串----");
        String s3 = "abc";
        String s4 = new String("abc");
        /*
         * s3 s4不同:
         * s3创建,在内存中只有一个对象
         * s4创建,在内存中有两个对象
         * */
        System.out.println(s3 == s4); //false
        //因为String复写了equals方法,建立字符串自己的判断相同的依据:通过字符串对象中的内容判断
        System.out.println(s3.equals(s4)); //true


        System.out.println("------字符串长度-------");
        String s5 = "abcdeacdb";
        System.out.println("len=" + s5.length());

        System.out.println("------字符串中某字符的位置------");
        int index = s5.indexOf('a'); // a第一次出现的位置
        System.out.println("'a'第一次出现的位置:" + index); //索引从0开始
        int index1 = s5.indexOf('a', index + 1); // a第二次出现的位置
        System.out.println("'a'第二次出现的位置:" + index1); //如果要找到字符不存在,则返回-1

        System.out.println("------获取指定位置上字符------");
        String s6 = "itcast";
        char ch = s6.charAt(3); // 不存在角标则返回StringIndexOutOfBoundsException
        System.out.println("ch=" + ch);

        System.out.println("------获取部分字符串------");
        String s7 = "welcometojavaworld";
        String s8 = s7.substring(2, 4); //包含头不含尾
        System.out.println("截取后为:" + s8);

    }
}

运行结果

在这里插入图片描述

  1. 对象比较用compareTo方法
  2. StringBuffer
  • 是一个字符串缓冲区(容器)
  • 长度可变,可任意类型(是将任意数据都转成字符串进行存储)
  • 容器对象提供很多对容器中数据的操作功能,如增删查改
  • 必须所有数据最终转换为一个字符串
  • 和字数组最大不同是:数组存储完可以单独操作每一个元素,每一个元素都是独立的;字符串缓冲区,所有存储的元素都被转为字符串,最后拼成一个大的字符串
	public class StringBufferDemo01 {
	    public static void main(String[] args) {
	        // 创建一个字符缓冲区对象,用于存储数据
	        StringBuffer sb = new StringBuffer();
	
	        // 添加数据。不断添加数据后,要对缓冲区的最后的数据进行操作,必须转为字符串
	        String str = sb.append(true).append("hello").toString();
	        System.out.println("数据:" + str);
	
	        System.out.println("---插入数据---");
	        StringBuffer sb1 = sb.insert(2, "it");
	        System.out.println("str: " + str);
	        System.out.println("插入后:" + sb1);
	
	        System.out.println("---删除数据---");
	        System.out.println("str: " + str);
	        StringBuffer sb2 = sb.delete(1, 4);
	        System.out.println("删除后: " + sb2);
	
	        System.out.println("---替代数据---");
	        System.out.println("str:" + str);
	        StringBuffer sb3 = sb.replace(1, 4, "cast");
	        System.out.println("替代后: " + sb3);
	
	        System.out.println("---设置长度(多余部分删除)---");
	        System.out.println("str: " + str);
	        sb.setLength(2);
	        System.out.println();
	
	
	    }
	}

运行结果

在这里插入图片描述

  • StringBuffer小练习
	public class StringBufferDemo02 {
	    public static void main(String[] args) {
	        /*
	         * int[] arr = [34, 12, 89, 68]
	         * 将一个int[]中元素转为字符串,格式为 [34, 12, 89, 68]
	         *
	         * */
	        // 缓冲区的应用:无论多少数据,什么类型,只要最终变成自字符串就可以使用StringBuffer这个容器
	        int[] arr = {34, 12, 89, 68};
	        String str = toString(arr);
	        System.out.println(str);
	    }
	
	    public static String toString(int[] arr) {
	        // 创建缓冲区
	        StringBuffer sb = new StringBuffer();
	
	        sb.append("[");
	        for (int i = 0; i < arr.length; i++) {
	            if (i != arr.length - 1) {
	                sb.append(arr[i] + ",");
	            } else {
	                sb.append(arr[i] + "]");
	            }
	        }
	
	        return sb.toString();
	    }
	}

运行结果

在这里插入图片描述

  • StringBuffer和StringBuilder异同
    • 功能完全相同
    • 区别:
      • StringBuilder是非同步的,单线程访问效率高
      • StringBuffer是同步的,多线程访问安全
  1. 基本类型包装类
  • 将基本数据类型值封装成对象,可以提供更多的基本操作数值的功能
byteByte
shortShort
intInteger
longLong
floatFloat
doubleDouble
booleanBoolean
charCharacter
  • 基本数据类型包装类特点

    • 用于在基本数据和字符串之间进行转换!
    解析方法:
    int parseInt(string);
    byte parseByte(string);
    boolean parseBoolean(string);
    xxx parseXxx(string);
    注:只有Character没有解析方法
    -----------------------
    字符串--->基本数值
    System.out.println(Integer.parseInt("123")+2); // 125
    System.out.println(Integer.parseInt("a1", 16); // 将十六进制“a1”转为十进制
    -----------------------
    基本数值--->字符串
    String.valueOf(35);
    Integer.toString(int);
    -----------------------
    基本数值--->包装对象
    Integer i = new Integer(4);
    Integer ii = new Integer("4");
    Integer iii = Integer.valueOf(4);
    -----------------------
    包装对象--->基本数值
    int num = i.intValue();
    
    System.out.println(Integer.MAX_VALUE);
    System.out.println(Integer.toBinaryString(-6)); // 十进制转二进制
    System.out.println(Integer.toHexString(-6)); // 十进制转为十六进制
    System.out.println(Integer.toOctalString(-6)); // 十进制转八进制
    
  • JDK1.5之后为简化书写引入包的新特性,自动装箱拆箱

	Integer i = 4; // 自动装箱。原理:Integer i = Integer i = Integer.valueOf(4);
	i = i + 5; // 原理: 等号右边:将i对象转为基本数值 i.intValue()+5;//自动拆箱。加法运算后,再次拆箱
  • 细节
	Integer x = 100;
	Integer y = 100;
	System.out.println(x == y); // true
	System.out.println(x.equals(y)); // true
	----------------------------------------------------
	Integer x = 128;
	Integer y = 128;
	System.out.println(x == y); // false
	System.out.println(x.equals(y)); // true
	----------------------------------------------------
	原因: 在JDK1.5中,如果数值在byte(-128~127)之内,不会新创建对象空间而是使用原来已有的空间
  • 基本类型包装类练习
	import java.util.Arrays;
	
	public class WrapperTest {
	    /*
	     * 将“23 9 -4 18 100 7”按照从小到大排序,生成一个数值有序的字符串
	     */
	    private static final String SPACE = " ";
	
	    public static void main(String[] args) {
	        String numsString = "23 9 -4 18 100 7";
	        numsString = sortNumberString(numsString);
	        System.out.println("nums = " + numsString);
	    }
	
	    private static String sortNumberString(String numsString) {
	        // 获取字符串中数字
	        String[] strs = numsString.split(SPACE);
	        // 将字符串转为int数组
	        int[] nums = parseIntArray(strs);
	        // 对数组进行排序
	        Arrays.sort(nums);
	        // 将数组转为字符串
	        return toString(nums);
	    }
	
	    private static String toString(int[] nums) {
	        StringBuilder sb = new StringBuilder();
	
	        for (int i = 0; i < nums.length; i++) {
	            if (i != nums.length - 1) {
	                sb.append(nums[i] + " ");
	            } else {
	                sb.append(nums[i]);
	            }
	        }
	        return sb.toString();
	    }
	
	    private static int[] parseIntArray(String[] strs) {
	        // 定义一个int数组
	        int[] arr = new int[strs.length];
	        // 遍历字符串数组,将元素转成int存储到arr中
	        for (int i = 0; i < strs.length; i++) {
	            arr[i] = Integer.parseInt(strs[i]);
	        }
	        return arr;
	    }
	}

运行结果

在这里插入图片描述


  1. 集合
  • 当有多个数据且数据个数不确定,可以使用集合,集合长度可变,集合里面存储的都是对象,并且对象类型可以不一致,可以有重复元素

  • 集合中存储到其实是对象的地址

  • 集合不可以存储基本数值,但JDK1.5后可以写,但实际存储的还是对象(基本数据类型包装类的对象),如coll.add(3); //coll.add(Integer.valueOf(3)); // 自动装箱

  • 存储时存储的对象提升为Object,取出时要使用元素的特有内容,必须向下转型

  • 元素取出方式
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

  • Collection:

    • List: 有序的,带索引的,通过索引就可以精确的操作集合中的元素,元素可以重复。List获取元素的方法有两种,一种是迭代,一种是遍历+get。List接口支持对元素进行增删改查
      增加 add(element) add(index, element)
      删除 remove(element) remove(index)
      修改 set(index, element)
      查询 get(index)
      • Vector: 可以增长的数组结构,同步的
      • ArrayList: 数组结构,长度可变(原理为创建新数组+复制数组),查询很快,增删较慢,不同步的
      • LinkedList: 链表结构,增删速度很快。可用于实现堆栈、队列
        堆栈:先进后出,First in Last Out(FILO)
        队列:先进先出,First in First Out ( FIFO)
    • Set : 不包含重复元素,不保证顺序。方法和Collection一致。Set集合只能通过迭代器取出元素
      • HashSet: 哈希表结构,不同步,保证元素唯一性的方式依赖于:hashCode()、equals()方法。查询速度快
        提高唯一性元素的查询效率,还想有序,可使用HashSet的子类LinkedHashSet

      • TreeSet: 可以对Set集合中的元素进行排序。使用的是二叉树结构,保证元素唯一性:使用的对象比较方法的结果是否为0,若是0则视为相同元素不存储
        元素的排序比较有两种方式:

        1. 元素自身具备自然排序,其实是实现了Comparable接口重写了compareTo方法。如果元素自身不具备自然排序,或者具备的自然排序不是所需要的,这时只能用第二种方式
        2. 比较器排序,其实是在创建TreeSet集合时,在构造函数中制定具体的比较方式。需要定义一个类实现Comparator接口,重写compare方法

        至此,在往集合中存储对象时,通常该对象都需要覆盖hashCode、equals,同时实现Comparable接口,建立对象的自然排序。通常还有一个方法也会复写:toString()

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
8. 在迭代过程中,不能使用集合的方法操作元素,可使用迭代器的子接口ListIterator操作

  • 通过List接口中的ListIterator()可以获取,该列表迭代器只有List接口有,且此迭代器可以完成在迭代过程中的增删改查动作
    在这里插入图片描述
    比较器小练习
// ComparatorByLength.java

	package CompareDemo;
	// 导入接口
	
	import java.util.Comparator;
	
	public class ComparatorByLength implements Comparator {
	    @Override
	    public int compare(Object o1, Object o2) {
	        String s1 = (String) o1;
	        String s2 = (String) o2;
	
	        int temp = s1.length() - s2.length();
	
	        return temp == 0 ? s1.compareTo(s2) : temp;
	    }
	}


// TreeSetTest.java

	import CompareDemo.ComparatorByLength;
	
	import java.util.Iterator;
	import java.util.Set;
	import java.util.TreeSet;
	
	public class TreeSetTest {
	    /*
	     * 要求:对字符串进行长度排序(由短到长)
	     * 思路分析:字符串之所以可以排序,因为是已经实现Comparable接口重写compareTo方法,建立了字符串的自然排序
	     * 但是自然排序不是需求中所需要的,需要自定义一个比较器
	     * */
	    public static void main(String[] args) {
	        Set set = new TreeSet(new ComparatorByLength());
	
	        set.add("abc");
	        set.add("haha");
	        set.add("xixi");
	        set.add("hiahia");
	        set.add("z");
	
	        for (Iterator it = set.iterator(); it.hasNext(); ) {
	            System.out.println(it.next());
	        }
	    }
	}

LinkedHashSetDemo

	import java.util.Iterator;
	import java.util.LinkedHashSet;
	import java.util.Set;
	
	public class LinkedHashSetDemo {
	    public static void main(String[] args) {

			/*
			* 提高唯一性元素的查询效率,还想有序,可使用HashSet的子类LinkedHashSet
			*/
	        Set set = new LinkedHashSet();
	
	        set.add("abcd");
	        set.add("hahahah");
	        set.add("java");
	        set.add("itcast");
	
	        for (Iterator it = set.iterator(); it.hasNext(); ) {
	            System.out.println(it.next());
	        }
	    }
	}
  • foreach循环 : 其实是增强for循环
    • 格式: for(元素的数据类型 变量:Collection集合or数组){ }
    • 用于遍历Collection和数组,通常只能遍历元素,不要在遍历的过程中做对集合元素的操作
    • 和普通for循环区别:新for循环必须有被遍历的目标,目标只能是Collecion或者是数组。
    • 遍历数组时,如果仅为遍历,可以使用增强for循环;如果要对数组的元素进行操作,使用普通for循环,因为可以通过索引操作
	List list = new ArrayList();
	list.add("a1");
	list.add("a2");
	list.add("a3");


	// 普通
	for(Iterator it = list.iterator();it.hasNext();){
		Object obj = it.next();
		System.out.println(obj);
	}
	// 新式
	for(Object obj: list){
		System.out.println(obj);
	}

在这里插入图片描述
上一篇:Java基础记录(四)

下一篇:Java基础记录(六)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

SimpleZihao

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值