知识点总结:Java核心技术(卷1)

2023-05-16

Java核心技术(卷1)

一、基础概念

1.1 基本程序设计结构

  • 1.1 数据类型

    • 1.1.1 数值类型

      • 1️⃣从java7开始,加上前缀0b或0B就可以写二进制;

      • 2️⃣指数的表示

        • 十进制中以10为底指数的表示:

          • double d = 1.0e+4; // 10000.0
          • double d2 = 100000.0e-4; // 10.0
        • 十六进制中以2位底指数的表示:

          • double a1 = 0x1.0p+3; // 8.0
          • double a2 = 0x1.0p-3; // 0.125
      • 3️⃣double中的严格浮点计算:strictfp

        • double类型使用64位存储一个数值,而有些处理器使用80位浮点寄存器。这些寄存器增加了中间过程的计算精度(将中间结果存储在80位寄存器中,将最终结果截断位64位)。这个过程增加了计算精度,但结果可能与始终在64位机器上计算的结果不一样。
        • 如果将一个类标记为strictfp,那么这个类的所有方法都要使用严格的浮点计算。
        • 严格浮点计算:所有的中间计算必须进行截断。
        • 默认情况下是不采用严格的浮点计算。
      • double类型的三个特殊值:增无穷大、负无穷大、NaN

        • Double.POSITIVE_INFINITY // 正无穷大

        • Double.NEGATIVE_INFINITY // 负无穷大

        • Double.NaN

          • 检查一个字符是否为数值:Double.isNaN(x)
    • 1.1.2 Unicode和char类型

      • Unicode

        • 专业术语

          • 码点:某个字符所对应的代码值;
          • Unicode中码点的表示:Unicode的码点可以分为17个级别,第一个级别,码点从U+0000到U+FFFF,被称为基本的多语言级别,其中包括经典的Unicode代码;其余的16个级别的码点从U+10000到U+10FFFF,其中包括一些辅助字符。
          • 代码单元:用8位或16位(UTF-8是8位表示,UTF-16用16位表示)字节来表示Unicode中基本的多语言级别,被称之为代码单元。也就是说,UTF-8中代码单元是8位字节,UTF-16中代码单元是16位字节。
        • UTF-16编码采用不同长度的编码表示所有的Unicode码点

          • 在UTF-16中,表示一个Unicode码点,需要一个或两个代码单元。
      • char类型

        • 在java中,char类型描述了UTF-16的一个代码单元

          • 因此,“char用来表示单个字符”的说法不完全正确。
        • char类型是用16位表示

        • 有些unicode字符可以用一个char值来描述,另一些Unicode字符需要用两个char值来描述。

      • 区分码点、代码单元的用途:

        • length() 方法

          • length方法将返回UTF-16编码表示的给定字符串所需要的代码单元数量。
        • 想要获取实际长度,即码点数量,即字符个数

          • String greeting = “hello”;
            int cpCount = greeting.codePointCount(0, greeting.length());
        • 获取第几个代码单元:

          • String greeting = “hello”;
            char first = greeting.atChar(0);
        • 获取第几个码点:

          • String greeting = “hello”;
            // i 为第i个码点,i从0开始
            int index = greeting.offsetByCodePoints(0, i);
            greeting.codePointAt(index);
    • 1.1.3 大数值: BigInteger和BigDecimal

      • BigInteger可以实现任意精度的整数运算;
        BigDecimal可以实现任意精度的浮点运算;
  • 1.2 规范

    • 1.2.1 变量

      • 关于“$”

        • 尽管$是一个合法的Java字符,但不要在自己的编码中使用这个字符,它只用在Java编译器或其他工具生成的名字中。
      • 关于“++”的使用

        • 建议不要在代码中使用“++”,这样的代码很容易让人困惑,而且会带来烦人的bug。
  • 1.3 运算符

    • 1.3.1 位运算符

      • 和<<运算符将位模式左移或右移

      • 运算符会用0填充高位;>> 会用符号位填充高位;不存在<<< 运算符;

      • 位运算符的右操作数要完成模32的运算(除非左操作数是long类型,这种情况下需要对右操作数模64):1<<35 等于1<<3 等于8
    • 1.3.2 运算符的级别

      • &&的优先级比|| 的优先级高
      • += 是右结合运算符,所以表达式: a+=b +=c 等价于: a+=(b+=c)
  • 1.4 String

    • 1.1 String是不可变字符串。一定不要使用“==”检测两个字符串是否相等,每次连接字符串,都会构建一个新的String对象;

      每次连接都会创建一个新的字符串,这样既耗时,又浪费空间。使用StringBuilder类就可以避免这个问题的发生。

      StringBuilder的前身是StringBuffer。StringBuffer效率稍微有些低,但允许采用多线程的方式执行添加或删除字符的操作。

      StringBuilder 除了能够apped字符串,还能添加代码单元,添加码点

      所有字符串都在一个单线程中编辑,则应该用StringBuilder代替它。

      • 编译器可以让字符串共享。如果虚拟机使用让字符串共享就可以使用“==”运算符检测两个字符串是否相等。但,实际上只是字符串常量可以共享,而+或substring等操作产生的结果并不共享。
      • “==”运算符能够用来确定两个字符串是否放在同一个位置。如果两个字符串放在同一个位置,它们必然相等。完全有可能将相同内容的字符串放在不同的位置上。
      • 使用equals 方法比较两个字符串是否相等。
    • 1.2 String 的length方法将返回采用UTF-16编码表示的给定字符所需要的代码单元数量

      • 要想获取实际的字符长度,即码点数量,可以调用:codePointCount 方法

      • public static void test04() throws UnsupportedEncodingException {
        String greeting = “Hello”;
        String codeStr = “\uD835\uDD46”;
        byte[] b = codeStr.getBytes(“UTF-16”);
        String s = new String(b, “UTF-16”);
        System.out.println(“greeting:”+greeting);
        System.out.println(“一个UTF-16编码的特殊符号s:”+s);
        System.out.println("greeting.length() : " + greeting.length()); // 打印出 5
        System.out.println("greeting.codePointCount() : " + greeting.codePointCount(0, greeting.length())); // 打印出5
        System.out.println("s.length() : " + s.length()); // 打印出 2
        System.out.println("s.codePointCount() : " + s.codePointCount(0, s.length())); // 打印出 1
        }

        • greeting:Hello
          一个UTF-16编码的特殊符号s:?
          greeting.length() : 5
          greeting.codePointCount() : 5
          s.length() : 2
          s.codePointCount() : 1
    • 1.3 连接字符串:join 方法,可以指定分界符

    • 1.4 所有字符串都属于CharSequence接口

  • 1.5 控制流程

    • “break 和 跳出标签”的用法:可以将标签应用到任何语句中,甚至可以应用到if语句或块语句中
  • 1.6 数组

1.2 对象和类

    • 在一个源文件中,只能有一个共有类,但可以有任意数目的非公有类。

    • 构造器

      • 构造器与类同名
    • finalize方法

      • 可以为任何一个类添加finalize方法。finalize方法将在垃圾回收器清楚对象之前调用(但是很难知道这个方法什么时候才能被调用)。
  • 对象

    • Java的对象都是在堆中创造;

    • ⚠️警告:不要编写返回引用可变对象的访问器方法。如果需要返回一个可变对象的引用,应该首先对它进行克隆(clone)。

      • // 错误代码示例
        /**
  • Date对象有一个更改器方法setTime。

  • 也就是说Date对象是可变的,这一点就破坏了

  • 封装性!
    */
    public Date gethireDay(){
    return this.hireDay;
    }
    - // 正确的做法
    public Date getHireDay(){
    return (Date)this.hireDay.clone();
    }

    • 封装:

      • 封装通常提供三项内容:

        • 一个私有的数据域;
        • 一个公有的域访问器方法;
        • 一个公有的域更改器方法;
      • 封装的好处:

        • 1️⃣可以改变内部实现;
        • 2️⃣更改器方法可以执行错误检查;
      • 警告:永远不要编写返回引用 可变对象 的方法器方法。

        • 如果要返回一个可变对象的引用,首先对其进行克隆,否则将破坏封装性;
        • 例如:
          LocalDate类没有更改器方法;
          Date对象是可变的
    • 调用构造器的具体处理步骤:

      • 0、静态域在类被加载的时候进行初始化。静态代码块在类第一次的时候执行一次。(创建对象的时候不再执行)

      • 1、所有数据域被初始化为默认值(0、false、或null);

      • 2、按照在类声明中出现的顺序,依次执行所有域初始化语句和初始化块;

        • 对于类的静态域进行初始化的代码比较复杂,可以使用静态的初始化块;
      • 3、如果构造器第一行调用了第二个构造器,则执行第二个构造器主体;

      • 4、执行这个构造器的主体;

  • 修饰符:

    • final 实例域

      • 可以将实例域声明为final,在构造对象的时候必出初始化这样的域;
      • final修饰符大都应用于基本(primitive)类型域,或不可变(immutable)类的域。对于可变的类,使用final修饰可能会对读着造成混乱
      • final 修饰的类不允许被继承;final修饰的方法不允许被覆盖;
      • 如果将一个类声明为final,只有其中的方法自动地成为final,而不包括域;
    • static 方法

      • 建议使用类名而不是对象名来调用静态方法,因为静态方法和对象没有任何关系。
      • 静态方法的另一种常见用途是使用静态工厂方法来构造对象。
  • 静态导入(import)

    • import语句不仅可以导入类,还增加了导入静态方法和静态域的功能
  • 其他

    • 编译运行带有包的源文件

      • 编译器在编译源文件的时候不检查目录结构,如果它不依赖其他包就不会出现编译错误。但如果编译后的类文件没有在声明的包下,程序最终无法运行。
    • 类路径

      • 类文件可以存储在JAR文件中。使用jar文件需要设置classpath
    • 文档注释:javadoc -d docDirectory nameofPackage1 nameofPackage2 ……

  • Java用于控制可见性的4个修饰符:

    • private 仅对本类可见;

    • public 对所有类可见;

    • protected 对本包和所有子类可见;

      • 如果子类和父类不再同一个包下,应当用子类对象访问父类protected方法;
    • 默认,不需要修饰符 对本包可见;

  • 类的加载:

    • 在启动时,包含main方法的类被加载。它会加载所需要的类。这些被加载的类又要加载它们需要的类,依次类推。

      对于一个大型的应用,可以使用技巧给用户一个启动速度比较快的幻觉:
      1、确保包含main方法的类没有显式地引用其他类;
      2、显示一个启动画面;
      3、通过调用Class.forName手工加载其他的类;

1.3 继承

  • 继承是Java的核心技术

  • super和this

    • 有些人认为super与this引用是类似的概念,实际上这样的比较并不恰当。因为super并不是一个对象的引用,不能讲super赋给另一个对象变量,它只是一个指示编译器调用超类方法的特殊关键字。

    • this的用途

      • 1、引用隐式参数;
      • 2、调用该类的其他的构造器;
    • super的用途

      • 1、调用超类的方法;
      • 2、调用超类的构造器;
  • 子类和超类

    • 子类

      • 子类构造器

        • 使用super调用构造器的语句必须是子类构造器的第一条语句;
        • 如果子类构造器没有显式调用超类构造器,将自动地调用该超类的默认构造器(没有参数的构造器)
        • 如果子类构造器没有显式的调用超类构造器,超类又没有不带参数的构造器,Java编译器将报告错误
    • 类型转化

      • 只能在继承层次内进行类型转化;
      • 在将超类转化为子类之前,应该使用instanceof进行检查;
      • 只有在使用子类特有方法的时候才需要类型转换
      • 一般情况下,应该尽量少用类型转换和instanceof运算符
  • 多态和动态绑定

    • 抽象类

      • 抽象类不能被实例化
    • 多态:

      • 一个引用类型的变量既可以引用当前类型的对象,也可以用子类型的对象;
    • 动态绑定

      • 理解方法的调用
  • 覆盖

    • 方法名字和参数列表称为方法的签名;
    • 允许子类将覆盖方法的返回类型定义为原返回类型的子类型。称之为“协变返回类型”
  • Object

    • 编写一个完美的equals方法

      • 设计原则,equals方法要满足五个特性:

        • 1、自反性;
        • 2、对称性;
        • 3、传递性;
        • 4、一致性;
        • 5、对于任意非空引用x,x.equals(null)方法应该返回false;
      • 设计思路:

        • 1、如果子类能够拥有自己的相等概念,则对称性要求将强制采用getClass进行检测;
        • 2、如果超类决定相等的概念,那么就可以使用instanceof进行检测,这样可以在不同子类的对象之间进行相等的比较。并应该将超类的equal方法声明为final;
      • 完美的equals方法的建议:

        • 1、显示参数命名为otherObject,稍后需要将它转换成另一个叫other的变量;

        • 2、检测this域otherObject是否引用同一个对象:if (this == otherObject) return true;

          • 这个比较只是一个优化;
        • 3、检测otherObject 是否为null,如果为null,返回false: if (otherObjct == null) return false;

          • 这个检测很有必要
        • 4、比较 this与otherObject 是否属于同一个类,如果equals的语义在每个子类中有所改变,就是用getClass检!= otherObject.getClass()) return false;

4、如果所有的子类都有统一的语义,就使用instanceof检测:
if (!(instanceof instanceof ClassName)) return false;

			- Java为每个类型管理了一个Class对象。因此,可以利用 == 运算符实现两个类对象比较的操作。

		- 5、将otherObject转化为相应的类型变量:

ClassName other = (ClassName) otherName;
- 6、现在开始对所有需要比较的域进行比较了。使用==比较基本类型域,使用equals比较对象域。所有的域都匹配返回true,否则返回false;
- 7、如果子类中重新定义equals,就要在其中包含调用super.equals(other)

	- 如果重新定义equals方法,就必须重新定义hashCode方法

- toString方法

	- 只要对象与一个字符串通过操作符“+”连接起来,Java编译器就会自动调用toString方法
	- 在调用x.toString() 的地方可以用""+x替代
	- println 方法就会直接调用x.toString() 并打印输出得到的字符串
	- 强烈建议为自定义的每一个类增加toString方法
  • 泛型数组列表ArrayList

    • ensureCapacity 方法

      • 这个方法为数组列表分配一个初始容器,这样向数组列表中添加元素时,添加元素数量不大于初始化容器大小时,数组列表不用重新分配空间
    • trimToSize 方法

      • 这个方法将存储区域的大小调整为当前元素数量所需要的存储空间数目。垃圾回收器将回收多余的存储空间。

1.4 对象包装器和自动装箱

  • 对象包装器是不可变的
  • 装箱和拆箱是编译器认可的,而不是虚拟机

1.5 枚举类

  • 在比较两个枚举类型的值时,永远不需要调用equals,而直接使用“==”就可以了

  • 所有的枚举类型都是Enum类的子类

  • 最有用的方法

    • toString() 这个方法能够返回枚举常量名

      • Size.SMALL.toString() 将返回字符串“SMALL”
    • valueOf() 这个方法是toString的逆方法

      • Size s = Enum.valueOf(Size.class, “SMALL”);
        将s 的值设置为 Size.SMALL
    • values() 这个方法返回一个包含全部枚举值的数组

    • ordinal() 这个方法返回enum声明中枚举常量的位置,位置从0开始计数。

二、Java的高级特性

2.1 反射

  • 能够分析类能力的的程序称为反射

    • 在运行时分析类的能力
    • 在运行时查看对象
  • 2.1.1 Class类

    • 一个Class对象实际上表示的是一个类型,而这个类型未必一定是一种类。例如:int不是类,但int.class 是一个class类型的对象

    • Java为每个类型管理了一个Class对象。因此,可以利用 == 运算符实现两个类对象比较的操作。

      • if(e.getClass() == Employee.class)
    • 创建一个类的实例

      • e.getClass().newInstance();
      • String s = “java.util.Random”;
        Object n = Class.forName(s).newInstance();
    • 利用反射分析类的能力

      • Class类中的getFields、getMethods、getConstructors 方法将分别返回类提供的public域、方法和构造器数组
      • Class类中的getDeclareFields、getDeclareMethods、getDeclareConstructors 方法将返回类中声明的全部域、方法和构造器
    • 实战:构建一个通用的toString 方法

2.2 接口

  • 基础概念:

    • 接口的所有方法自动地属于public
    • 接口中不能包含实例域或静态方法,但却可以包含常量。接口中的域将被自动设为public static final;
    • 接口中的方法标记为public,接口中的域将被自动设为public static final。
      Java语言规范建议不要书写这些多余的关键字。
    • 每个类只能拥有一个超类,但却可以实现多个接口;
    • 使用instanceof 检查一个对象是否属于某个特定类,也可以使用使用instanceof 检查一个对象是否实现了某个特定的接口
    • 使用逗号将实现(implement) 的各个接口分隔开;
  • 抽象类和接口

    • 抽象类表示通用属性,有一个问题;每个类只能扩展于一个类;
    • 接口可以提供多重继承的大多数好处,同时还能避免继承的复杂性和低效性。
  • 新认识:

    • 静态方法

      public interface Path{
      public static Path get(String first, String …more){
      return FileSystem.getDefault().getPath(first,more);
      }
      }

      • 在Java8中,允许在接口中增加静态方法。
      • 通常是将静态方法放到伴随类中。在标准库中,可以看到成对出现的接口和实用工具类,如:
        Collection/Collections
      • 以后在实现自己的接口时,不再需要为实用工具方法另外提供一个伴随类。
    • 默认方法

      public interface Comparable {
      default int compareTo(T other){return 0;}
      }

      • 可以为接口方法提供一个默认实现。必须使用default修饰符标记这样一个方法。

      • 默认方法可以调用任何其他方法

      • 默认方法的一个重要用途是“接口演化”

        • 为旧的接口类添加一个新的默认方法,这样可以兼容旧的代码;
      • 解决默认方法的冲突:

        • 1)超类优先;
          如果超类提供了一个具体方法,同名而且有相同参数类型的默认方法会被忽略;
        • 子主题 3
        • 2)接口冲突;
          如果一个超接口提供了一个默认方法,另一个接口提供了一个同名而且参数类型(不论是否为默认方法)相同的方法,必须覆盖这个方法来解决冲突;
  • 标记接口:

    • 标记接口唯一的作用就是允许在类型检查中使用 instanceof
    • 建议自己的程序中不要使用标记接口
  • 函数式接口:只有一个抽象方法的接口

    • 常用的函数式接口
    • 基本的函数式接口

2.3 lambda表示式、方法引用、构造器引用

  • 概要:

    • lambda表达式是一个可传递的代码块,可以在以后执行一次或多次。

    • 函数式接口:只有一个抽象方法的接口

    • 在java中,lambda表达式所能做的也只是能转换为函数式接口。

    • 想要用lambda表达式做某些处理,还是要谨记表达式的用途,为它建立一个特定的函数式接口。

    • ArrayList类有一个removeIf方法,它的参数就是一个Predicate。这个接口专门用来传递lambda表达式。

      • // 删除数组列表中为null的值
        list.removeIf(e->e==null);
  • lambda 表达式的形式及组成:

    • lambda 表达式形式:参数,箭头(->)以及一个表达式

    • lambda有三部分构成:

      • 1)一个代码块;
      • 2)参数;
      • 3)自由变量的值,这里指非参数而且不在代码中定义的变量;
    • 代码块以及自由变量有一个术语,叫:闭包

      • lambda就是Java的闭包
    • lambda表达式可以捕获外围作用域中变量的值。但这里有一条规则:lambda表达式中捕获的变量必须实际上是最终变量。实际变量是指,这个变量初始化之后就不会再为它赋新值。

      • lambda表达式中引用的变量值,既不能在lambda表达式中改变,也不应该在外部改变。
    • lambda中不能有同名的局部变量;

    • lambda 表达式中使用this关键字时,是指创建这个lambda表达式的方法的this参数。

      • 例如:
        public class Application(){
        public void init(){
        ActionListener listener = event -> {
        System.out.println(this.toString());
        }
        }
        }

这里的this指的是ActionListener

  • lambda 表达式补充:

    • lamdba表示式的返回类型总是由上下文推导得出;
    • 需要函数式接口的时候,可以提供一个lambda表达式代替;
    • 最好把lambda表示式看做函数,而不是一个对象。lambda表达式可以转换为接口
    • 想要用lambda表达式做某些处理,还是要谨记表达式的用途,为它建立一个特定的函数式接口。
    • lambda表达式的重点是延迟执行
  • 方法引用

    有些时候已经有现成的方法可以完成你想要传递到其他代码的某个动作。

    • 方法引用,主要有三种情况:

      • object::instanceMethod

        • 如:
          System.out::println
          等价于
          x -> System.out.println(x)
      • Class::staticMethod

        • 如:
          Math::pow
          等价于
          (x,y) -> Math.pow(x,y)
      • Class::instanceMethod

        • 第一个方法会成为方法的目标
        • 如:
          String::compareToIgnoreCase
          等价于
          (x,y) -> x.compareToIgnoreCase(y)
    • 方法引用中可以使用this和super

      • 如:
        this::equals
        等价于
        x->this.equals(x)
      • super::greet
  • 构造器引用

    • 例如:Person::new 是Person构造器的一个引用
    • int[]::new 等价于 x->new int[x]

2.4 内部类

  • 为什么使用内部类:

    • 内部类方法可以访问该类定义所有的作用域中的数据,包括私有的数据;
    • 内部类可以对同一个包中的其他类隐藏起来
    • 当想要定义一个回调函数且不想编写大量代码时,使用匿名内部类比较便捷
  • 内部类既可以访问自身的数据域,也可以访问创建它的外围类对象的数据域。

  • 只有内部类可以是私有类,而常规类只可以具有包可见性,或公有可见性。

  • 内部类中所有的静态方法域都必须是final

  • 内部类不能有static方法

  • 只有内部类可以声明为static

    • 在内部类不需要访问外围类对象的时候,应该使用静态内部类。
  • 内部类的种类

    • 局部内部类

      • 如果一个内部类只在被一个方法访问,就可以将这个内部类定义到方法中。
      • 局部类有一个优点:它们不仅能够访问包含它们的外部类,还可以访问局部变量;在JavaSE8 之前,局部变量声明为final;
    • 匿名内部类

      • 如果定义在方法中的内部类只创建一个对象,就可以使用匿名内部类替代。
      • 尽可能使用lambda表达式代替匿名内部类
    • 静态内部类

      • 有时候,使用内部类只是把一个类隐藏在另一个类的内部,并不需要内部类引用外围类对象。
        为此,可以将内部类声明为static,以便取消产生的引用。

2.5 代理

  • java的JDK里面提供了动态代理的方案

2.6 Java的异常

  • 异常的层次结构:

    • 所有异常都是由Throwable继承而来,
      而下一层立即分为两类:Error和Exception

    • Exception层又分解为两支:一支派生于RuntimeException,另一支包含其他异常

      • 由程序错误导致的异常属于RuntimeException

        • 如果RuntimeException出现,一定是你的问题
      • 而程序本身没问题,但由于像I/O错误这类问题导致的异常属于其他异常

  • 受查异常和非受查异常

    • 派生于Error类或RuntimeException类的所有异常称为非受查异常;
    • 所有其他异常称为受查异常
  • 策略:一个方法必须声明所有可能抛出的受查异常,而非受查异常要么不可控(Error),要么就应该避免发生。

  • 合并catch语句

    • 形式: catch(XXXException | XXXException e)


      • catch (IOException|InterruptedException|ClassNotFoundException e) {
        e.printStackTrace();
        throw new RuntimeException(e);
        }
    • 只有当捕获的异常类型彼此之间不存在子类关系时才需要这个特性。

    • 捕获多个异常时,异常变量隐含为final变量,不能再子句体中为e赋不同的值。

  • 再次抛出异常,可以将原始异常设置为新异常的原因

    • 例如:
      Throwable se = new ServletException(“database error”);
      se.initCase(e);
      throw se;
    • 重新得到原始异常:Throwable e = se.getCase();
  • 强烈建议将try/catch和try/finally语句块解耦,这样可以提高代码的清晰度。

    • try{
      try{
      code that might throw exceptions
      }finally{
      in.close();
      }
      }catch(IOException e){
      show error message
      }
  • 带资源的try语句

    • 最简单的形式如:
      try (Resource res = …)
      {
      work with res
      }
    • 还可以指定多个资源:
      try (Scanner in = new Scanner(new FileInputStream("/user/words"),“UTF-8”);
      PrintWriter out = new PrintWriter(“out.txt”)){

}

	- 无论这个块如何退出,in和out都会关闭

2.7 泛型程序设计

  • 2.7.1 泛型类

    • public class Pair
  • 2.7.2 泛型方法

    • 例如:
      public static getMiddle<T… a>
    • 类型变量放在修饰符后面,返回类型的前面;
  • 2.7.2 类型变量的限定

    • 例如:
      public static T min(T[] a)…

      • 将T限定为实现了Comparable接口的类
    • 一个类型变量使用通配符可以有多个限定:
      T extends Comparable & Serializable

    • 为了提高效率,应该将标签(tagging)接口(即没有方法的接口)放在边界列表的末尾

  • 2.7.3 类型擦除

    • 虚拟机没有泛型类型对象。
    • 无论何时定义一个泛型类型,都自动提供了一个响应的原始类型。原始类型的名字就是删去类型参数后的泛型类型名。擦除类型变量,并替换为限定类型(无限定的变量用Object)
    • 为了提高效率,应该将标签(tagging)接口(即没有方法的接口)放在边界列表的末尾
  • 2.7.4 通配符类型

    • 例如:
      Pain<? extends Employee>

      • 表示任何泛型Pain类型
    • 通配符限定与类型限定十分类似

    • 但,通配符限定有一个附加能力,可以指定一个超类型限定,如:? super Manager ,这个通配符限制为Manager的所有超类型

  • 2.7.5 无限定通配符

    • class Pair<?>{
      ? getFirst()
      void setFirst(?)
      }

      • getFirst() 的返回值只赋给一个Object。setFirst方法不能被调用,甚至不能用Object调用。可以调用 setFirst(null)
    • 用来测试一个pair是否包含一个null引用

    • 非法的代码:? t = p.getFirst();// Error

2.6 应用首选项的存储

三、图形程序设计

3.1 Swing

  • 解释:“被绘制的”用户界面类。

3.2 AWT

  • 解释:像事件处理这样的窗口工具箱的底层机制。

四、部署Java应用程序

4.1 Jar文件

  • 4.1.1 创建Jar文件;

  • 4.1.2 清单文件;

  • 4.1.3 可执行Jar文件;

    • java -jar jar文件

4.2 应用首选项的存储

  • 4.2.1 属性映射

    • Properties
  • 4.2.2 首选项API

五、集合

集合框架的接口

  • Iterable

    接口

    • Collection

      Collection 是接口。
      Collection实现Iterable的接口,这样就能够使用for each 语法了

      • List
      • Set
      • Queue
  • Map

    • SortMap

      • NavigableMap
  • Iterator

    • ListIterator

集合框架中的类

  • AbstractCollection

    • AbstractList

      • AbstractSequentialList

        • LinkedList
      • ArrayList

        数组和数组列表都有一个重大的缺陷。这就是从数组的中间位置删除一个元素要付出很大的代价。在数组中间的位置上插入一个元素也是如此。

        链表(Linked list) 解决了这个问题。

    • AbstractSet

      • HashSet

        • LinkedHashSet
      • EnumSet

      • TreeSet

    • AbstractQueue

      • PriorityQueue
      • ArrayQueue
  • AbstractMap

    • HashMap

      • LinkedHashMap
    • TreeMap

    • EnumMap

    • WeakHashMap

    • IdentityHashMap

队列

  • 双端队列

  • 优先级队列

    • 使用优先级队列的典型示例是任务调度

链表

  • 在Java程序设计语言中,所有链表实际上都是双向连接的。
  • LinkedList对象根本不做任何缓存位置信息的操作。每次查找一个元素都要从列表的头部重新开始搜索。
  • 使用链表的唯一理由是尽可能减少在列表中间插入或删除元素所付出的代价。

数组列表

散列集

  • 散列表可以快速查找所需要的对象。

  • 原理:在Java中,散列表用链表数组实现。每个列表称为桶。要想查到表中对象的位置,就要先计算它的散列码,然后与桶的总数取余,所得的结果就是保存这个元素的桶的索引。

    • 散列码:hashCode
    • Java8中,桶满时会从链表变为平衡二叉树。
    • 初始化桶数
    • 散列因子
  • HashSet类,实现了基于散列表的值。

树集

  • TreeSet

    • 树集是一个有序集合
    • 排序是用树结构完成的

映射

  • 用迭代处理映射的键和值

    • scores.forEach((k,v) -> System.out.println(“key=”+k + “,value” + v));
  • HashMap和TreeMap

    两个通用的实现。

    • HashMap,对键进行散列
    • TreeMap,用键的整体顺序对元素进行排序,并将其组织成搜索树。
  • 要迭代处理映射的键和值,最容易的方法是使用forEach方法。可以提供一个接收键和值的lamdba表达式。

    • scores.forEach((k,v)->System.out.println(“key=”+k+",value="+v));
  • LinkedHashMap

    • 链接散列映射将用访问顺序,而不是插入顺序,对映射条目进行迭代。

      • 每次调用get或put,受到影响的条目将从当前位置删除,并放到条目链表的尾部(只有条目在链表中的位置会受影响,而散列表中的桶不会受影响。一个条目总位于与键散列码对应的桶中)。
  • WeekHashMap

    • 这个数据结构将与垃圾回收期协同工作,用于回收不再有任何途径引用的键值
  • IdentityHashMap

    • 键的散列值不使用hashCode函数计算的,而是用System.identityHashCode方法计算。而且对两个对象进行比较时,IdentityHashMap类使用==,而不使用equals。

视图与包装器

  • 映射类keySet() 返回一个实现了Set接口的类对象,这个类的方法对原映射进行操作。这种结合称为视图。

  • Arrays类的静态方法asList将返回一个包装了普通Java数组的List包装器。
    Card[] cardDeck = new Card[52];
    List cardList = Arrays.asList(cardDeck);
    返回的对象不是ArrayList。它是一个视图对象。

  • 同步视图

    • Collections.synchronizedMap方法可以将任何一个映射表转换成具有同步访问方法的Map
  • 受查视图

    • List safeStrings = Collections.checkedList(strings, String.class);
      ArrayList rawList = safeStrings;
      rawList.add(new Date()); // checked list throws a ClassCastException

Properties

  • 一个非常特殊的映射结构

栈 Stack

位集 BitSet

  • 由于位集将位包装在字节里。所以,使用位集要比使用Boolean对象的ArrayList更加高效。
  • 案例:查找所有的素数

六、并发

线程

  • 多进程和多线程的区别

    • 本质区别在于每个进程拥有自己的一整套变量,而线程则共享数据
  • 开启一个线程

    • 方案一:实现Runnable接口

      • lambda方式

        • Runnable r = ()->{System.out.println(“I have a dream.”);};
          Thread t = new Thread®;
          t.start();
      • 内部类方式

        • Thread t = new Thread(new Runnable(){
          @Override
          public void run() {
          System.out.println(“This is inner class”);
          }
          });
          t.start();
    • 方案二:构建一个Thread类的子类

      • 内部类方式

        • new Thread(){
          @Override
          public void run() {
          System.out.println(“I love you.”);
          }
          }.start();
      • 继承的方案

        • class MyThread extends Thread{
          @Override
          public void run() {
          System.out.println(“This extend Thread”);
          }
          }
        • Thread thread = new MyThread();
          thread.start();

中断线程

  • 每个线程都应该不时地检查这个标志,以判断线程是否被中断

  • 发送中断请求 interrupt()

    • interrupt() 方法用于请求终止线程。当对一个线程调用interrupt方法时,线程的中断状态将被置位
  • 异常

    • 在一个被阻塞的线程(调用sleep或wait)上调用interrupt方法时,阻塞调用将会被Interrupted Exception异常中断。
    • 如果中断状态被置位时调用sleep方法,它不会休眠。相反,它将清除这一状态(!)并抛出InterruptedException
  • 检查当前线程,并将中断状态重置为false

    • static boolean interrupted()
  • boolean isInterrupted()

    • 检查当前线程是否被终止

线程的状态

  • New 新创建

    new Thread®

    • Runnable 可运行

      一旦调用start方法,线程处于runnable状态

      • 被阻塞线程和等待线程

        实际上被阻塞状态与等待状态时有很大不同的

        • Blocked 被阻塞

          当一个线程试图获取一个内部的对象锁,而该锁被其他线程持有,则该线程进入阻塞状态。

          当所有其他线程释放该锁,并且线程调度器允许本线程持有它的时候,该线程将变为非阻塞状态。

        • Waiting 等待

          在调用Object.wait 方法或Thread.join 方法,或者等待java.util.concurrent 库中的Lock或Condition时,就会出现这种情况。

        • Timed waiting 计时等待

          带有超时参数的方法:
          Thread.sleep、Object.wait、Thread.join、Lock.tryLock以及Condition.await的计时版

      • Terminated 被终止

        原因一: run方法正常退出而自然死亡;
        原因二: 因为一个没有捕获的异常终止了run方法而意外死亡

线程的属性

  • 线程的优先级

    • 在Java程序设计语言中,每一个线程有一个优先级
    • 默认情况下,一个线程集成它父线程的优先级
    • 可用setPriority方法提高或降低任何一个线程的优先级
    • 每当线程调度器有机会选择新线程时,它首先选择具有较高优先级的线程。
    • 线程优先级是高度依赖于系统的。不要将程序构建为功能的正确性依赖于优先级。
    • static void yield() 导致当前执行线程处于让步状态
  • 守护线程

    • 守护线程的唯一用途是为其他线程提供服务。

      • 例如:计时线程,它定时发送“计时嘀嗒”信号给其他线程或清空过时的高速缓存项的线程。
    • 当只剩下守护线程时,虚拟机就退出了,由于如果只剩下守护线程,就没必要继续运行程序了。

    • 守护线程应该永远不去访问固有资源,如文件、数据库,因为它会在任何时候甚至在一个操作的中间发生中断。

    • setDaemon(boolean isDaemon),标记为守护线程,该方法必须在线程启动之前调用

  • 未捕获异常处理器

    • 当线程发生异常终止的时候,异常会被传递到一个用于未捕获异常的处理器。

    • 处理器必须实现一个Thread.UncaughtExceptionHandler接口的类

      • 这个接口只有一个方法:void uncaughtException(Thread t, Throwable e)
    • 安装线程处理器

      • 可以使用setUncaughtExceptionHandler()方法为任何线程安装一个处理器

        • Thread t = new Thread(()->{int i=1/0;});
          t.setUncaughtExceptionHandler((tt, e)->{System.out.println(“There has exception.”);});
          t.start();
      • 也可以用Thread类的静态方法setDefaultUncaughtExceptionHandler为所有线程安装一个默认的处理器

同步

  • 背景:在多线程应用中,两个或两个以上的线程需要共享对同一数据的存取。

  • 进行同步的两种机制

    • 方案一:synchronized关键字,同步方法

      • synchronized关键字自动提供一个锁以及相关的“条件”
    • 方案二: 使用锁

    • 方案三: 同步代码块

  • 锁对象

    • 方案二:ReentrantLock类, jdk1.5提供

      • ReentrantLock()

      • ReetrantLock(boolean fair)

        • 创建一个公平策略的锁。一个公平锁偏爱等待时间最长的线程。但这一公平的保证将大大降低性能。所以,默认情况下,锁没有被强制为公平的。
      • myLock.lock();// a ReentrantLock object
        try{
        critical section
        }finally{
        // make sure that lock is unlocked even if an exception is thrown
        myLock.unlock();
        }

    • 概述

      • 锁用于保护代码片段,任何时刻只能有一个线程执行被保护的代码
      • 锁可以用户一个或多个相关的条件对象
      • 使用锁就不能使用带资源的try语句
  • 条件对象

    • Condition

      • Condition condition = bankLock.newCondition();
    • 每个条件对象管理哪些已经进入被保护的代码段但还不能运行的线程。

    • bankLock.lock();
      try{
      while(condition){
      condition.await();
      }
      critical section
      condition.signalAll();
      }finally{
      bankLock.unlock();
      }

  • synchronized 方法

    • 从jdk1.0 版本,Java中的每一个对象都有一个内部锁。如果一个方法用synchronized关键字声明,那么对象的锁将保护整个方法。 也就是说,要调用方法,线程必须获得内部锁的对象锁。

    • 案例:

      • public synchronized void transfer(int from, int to, double amount) throws InterruptedException{
        // 加条件锁
        while (accounts[from] < amount) {
        wait();
        }
        System.out.println(Thread.currentThread());
        accounts[from] -= amount;
        System.out.printf(" %10.2f from %d to %d", amount, from, to);
        accounts[to] += amount;
        System.out.printf(" Total Balance: %10.2f%n", getTotalBalance());
        notifyAll();
        }
  • synchronized 代码块

    • private Object lock = new Object();
      public void method(){
      synchronized(lock){
      critical section
      }
      }

      • 这里lock对象被创建仅仅是用来使用每个Java对象持有的锁。
  • volatile 域

    • 在一个域上声明volatile,那么编译器和虚拟机就知道该域是可能被另一个线程并发更新的。
  • final变量

    • final Map<String, Double> accounts = new HashMap<>();

      • 其他线程会在构造函数完成构造之后才看到这个accounts变量。
  • 原子性

    • java.util.concurrent.atomic包中有很多类使用了很高效的机器级指令(而不是使用锁)来保证其他操作的原子性。
  • 死锁

  • 线程的局部变量

    • 使用ThreadLock辅助类为各个线程提供各自的实例

    • 例如: SimpleDateFormat不是线程安全的。
      public static final SimpleDateFormat dataFormat = new SimpleDateFormat(“yyyy-MM-dd”);
      如果两个线程都执行以下的操作:
      String dateStamp = dateFormat.format(new Date());
      dateFormat 使用的内部数据结构可能会被并发的访问破坏。

      • 可以使用同步,但开销很大;也可以在需要的时候创建一个局部的SimpleDateFormat对象,不过这也太浪费了。

      • 可以使用以下代码,为每个线程创建一个实例:

        • public static final ThreadLocal dateFormat = ThreadLocl.withInitial(()->new SimpleDateFormat(“yyyy-MM-dd”));
        • 要访问具体的格式化方法,可以调用:
          String dateStamp = dateFormat.get().format(new Date());
    • java.util.Random类是线程的。但如果多个线程需要等待一个共享的随机数生成器,这会很低效。可以使用ThreadLocal辅助类为各个线程提供一个单独的生成器。

      • 不过jdk1.7 提供了一个便利类。只需要做以下调用:
        int random= ThreadLoclRandom.current().nextInt(upperBound);

        • ThreadLoclRandom.current() 调用会返回特定于当前线程的Random类实例。
  • 锁测试与超时

    • myLock.tryLock()

      • tryLock方法视图申请一个锁,在成功获得锁后返回true,否则立刻返回false,而且线程可以立刻离开去做其他事情。
    • myLock.tryLock(100, TimeUnit.MiLLISECONDS))

    • myLock.await(100, TimeUnit.MiLLISECONDS))

  • 读/写锁

    • ReentrantReadWriteLock

    • 很多线程从一个数据结构读取数据而很少线程修改器数据的话,ReentrantReadWriteLock是十分有用的。

    • 步骤

      • // 构建对象
        priavte ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
        // 获取读锁和写锁
        private Lock readLock = rwl.readLock();
        private Lock writeLock = rwl.writeLock();

      • 对读方法加读锁

      • 对写方法加写锁

        • public void transfer(){
          writeLock.lock();
          try(){}
          finally{writeLock.unLock();}
          }
  • 弃用stop和suspend方法

    • 这两个方法有一些共同点:都试图控制一个给定线程的行为
    • stop方法天生不安全,无法知道什么时候调用stop方法是安全,什么时候导致对象破坏
    • suspend方法容易导致死锁

阻塞队列

阻塞队列就是线程安全的集合。

  • 背景

    • 对于实际编程应该尽量远离底层。
    • 对于多线程问题,可以通过使用一个或多个队列以优雅且安全的方式将其形式化。
  • java.util.concurrent

    • LinkedBlockingQueue

      • 容量是没有上边界的,但是也可以选择指定最大容量
    • LinkedBlockingDeque

      • 是一个双端版本
    • ArrayBlockingQueue

      • 在构造时需要指定容量,并且有一个可选的参数来指定是否需要公平性。通常公平性会降低性能,只有在确实非常需要时才使用它。
    • PriorityBlockingQueue

      • 一个带有优先级的队列,而不是先进先出队列。元素按照它们的优先级顺序被移出。该队列是没有容量上限,但是,如果队列是空的。取元素的操作会阻塞
    • DelayQueue

      • 实现了Delayed接口。getDelay方法返回对象的残留延迟。负值表示延迟已经结束。元素只有在延迟用完的情况下才能从DelayQueue移出。
      • 同时还必须实现compareTo方法,DelayQueue使用该方法对元素进行排序。
    • TransferQueue 接口(jdk1.7 增加)

      • LinkedTransferQueue

      • 这个接口,允许生产者线程等待,直到消费者准备就绪可以接受一个元素。

        • 如果生产者调用q.transfer(item) 这个调用会阻塞,直到另一个线程将元素删除。
  • 使用

    • 第一类

      • 将队列当做线程管理工具来使用,put和take方法
    • 第二类

      • 当试图向满的队列中添加或从空的队列中移出元素时,add、remove和element操作会抛出异常
    • 第三类

      • offer、poll、和peek方法

        • 这些方法如果不能完成任务,只是给出一个错误提示而不会抛出异常。

线程安全的集合

  • 高效的映射、集、队列

    • java.util.concurrent

      • ConcurrentHashMap
      • ConcurrentSkipListMap
      • ConcurrentSkipListSet
      • ConcurrentLinkedQueue
    • 确定这样的集合当前的大小通常需要遍历

  • 同步包装器

    • 任何集合类都可以通过同步包装器(synchronizationwrapper)变成线程安全的

      • List synchArrayList = Collections.synchronizedList(new ArrayList();
      • Map<K, V> synchHashMap = Collections.synchronizedMap(new HashMap<K, V>());
    • 如果在另一个线程可能进行修改时要对集合进行迭代,仍然需要使用“客户端”锁定

      • synchronized(synHashMap)
        {
        Iterator iter = synHashMap.keySet().iterator();
        while(iter.hasNext)…
        }

Runnable、Callable和Future

  • Runnable封装一个一部运行的任务,可以将其想象成为一个没有参数和返回值的异步方法。

  • Callable与Runnable类型,但是有返回值。Future 保存异步计算的结果

    • Callable接口是一个参数化的类型,只有一个方法call

      • public interface Callable{
        V call() throws Exception;
        }
    • 可以启动一个计算,将Future对象交给某个线程,然后忘掉它。Future对象的所有者在计算好之后就可以获得它。

  • 分析Future的方法

    • get() throws…

      • 这个get方法的调用被阻塞,直到计算完成
    • get(long timeout, TimeUnit unit) throws…

      • 这个方法调用超时时,会抛出TimeoutException异常
    • 如果在运行过程中,线程被中断,两个方法都将抛出InterruptedException。如果计算已经完成,那么get方法立刻返回

  • FutureTask 包装器

    • 可以将Callable转换成Future和Runnable

线程池

  • 使用线池的好处

    • 1、减少并发线程的数目;
    • 2、一个线程可以多次提供服务;
  • 通过执行器类Executor的静态方法来构建线程池

    • newCachedThreadPool

      • 必要时创建新线程;空闲线程会被保留60秒;
    • newFixedThreadPool

      • 创建固定数量的线程,空闲线程会一直被保留
    • newSingleThreadExecutor

      • 只有一个线程的“池”,该线程顺序执行每一个提交的任务
    • 预执行器

      • newScheduledThreadPool

        • 用于预定执行而构建的固定线程池
      • newSingleThreadScheduledExecutor

        • 用于预定执行而构建的单线程“池”
      • 为预定执行或重复执行任务而设计

  • 实现线程池的步骤

    • 第一步:调用Executor类中静态方法创建线程池

    • 第二步:调用线程池submit方法提交Runnable或Callable对象;

    • 第三步:保存好返回的Future对象

    • 第四步:当不再提交任何任务的时候,调用shutdown方法。关闭线程池

      • 调用shutdown方法,执行器关闭,不再接受新的任务。当所有任务都完成以后,线程池中的线程死亡。
      • 另一个中方法是调用shutdownNow,该池取消尚未开始的所有任务并试图中断正在运行的线程
  • 控制任务组

    • 有时,使用执行器更有实际意义的原因,控制一组相关任务

      • 可以提交很多任务,每个任务使用一种方法处理一个问题,只要其中一个任务得到答案,计算停止(调用 shutdownNow方法)
    • invokeAny

      • 提供所有对象到一个Callable对象的集合中
      • List<Callable> tasks = …;
        List<Future> results = executor.invokeAll(tasks);
        for(Future result: results) processFurthrer(result.get())
    • ExecutorCompletionService

      • 对结果按可获得的顺序保存起来
  • Fork-Join框架

    • 讲一个大任务拆分成一个个小任务,最后将结果汇总

    • 步骤

      • 步骤一:扩展一个RecursiveTask类,或扩展RecursiveAction类;

        • invokeAll方法接收到很多任务并阻塞
        • 对每个子任务应用join,并返回其合计的结果
      • 第二步:创建ForkJoinPool 对象,并调用invoke方法提交recursiveTask

        • join方法返回结果

同步器

七、书籍推荐

看以下三本书籍,更有利于理解并发

  • 《Java编程思想》

    • D瓜哥:推荐先读并发那章
  • 《Effective Java》

    • D瓜哥:还可以看看中关于并发的描述
    • 左耳朵狮子:如果C和OS基础不错,可以直接看effective java
  • 现代操作系统 或 操作系统精髓

XMind: ZEN - Trial Version

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

知识点总结:Java核心技术(卷1) 的相关文章

  • PX4与Gazebo、ROS/MAVROS以及QGC地面站之间的通信

    PX4与Gazebo ROS MAVROS以及QGC地面站之间的通信 一 整体框架 ROS xff08 机器人操作系统 xff09 可用于PX4和Gazebo模拟器 它使用MAVROS MAVLink节点与PX4通信 ROS Gazebo与
  • 四旋翼飞行器控制模型公式推导

    四旋翼飞行器控制模型 为便于建立模型 xff0c 现对四旋翼飞行器进行以下假设 xff1a 1 四旋翼飞行器是均匀对称的刚体 2 四旋翼飞行器的质量和转动惯量不发生改变 3 四旋翼飞行器的几何中心与其重心重合 4 四旋翼飞行器只受重力和螺旋
  • java中几种读取配置文件的方法

    java读取 properties配置文件的几种方法 xff08 1 xff09 Properties类读取 Properties类继承自Hashtable类并且实现了Map接口 xff0c 也是使用一种键值对的形式来保存属性集 不过Pro
  • Java项目分层

    MVC模式 在实际的开发中有一种项目的程序组织架构方案叫做MVC模式 xff0c 按照程序 的功能将他们分成三个层 xff0c 如下图 xff1a Modle层 xff08 模型层 xff09 View层 xff08 显示层 xff09 C
  • 简单介绍控制理论(经典、现代)

    1 经典和现代的区别和联系 xff08 1 xff09 区别 研究对象 经典控制系统一般局限于单输入单输出 线性定常系统 主要分为开环控制系统和闭环控制系统 严格的说 xff0c 理想的线性系统在实际中并不存在 实际的物理系统 xff0c
  • 框架中<include>**/*.xml</include>配置解释

    在mybatis Spring SpringMVC SpringBoot等框架的配置文件中经常会使用到如下代码 xff1a lt resource gt lt directory gt src main java lt directory
  • 反转单链表的几种方式对比(包括双指针法和递归)

    需求 xff1a 给你单链表的头节点 head xff0c 请你反转链表 xff0c 并返回反转后的链表 方式一 xff1a 双指针法 建立一个虚拟节点 class Solution public ListNode reverseList
  • 正则表达式 ^$ 同时出现代表什么

    与 同时出现在正则前后表示什么 xff1f 脱字符 xff1a 匹配开头 xff0c 若存在多行匹配多行的行头 美元符 xff1a 匹配尾部 xff0c 若存在多行匹配多行的尾部 同时写时只是限制字符的起点与终点 xff0c 比如 xff1
  • 设置虚拟机为固定IP,避免每次启动虚拟机都会分配新的IP地址

    采用一种最简单的方式 xff0c 通过修改配置文件来指定IP xff0c 并可以连接到外网 要求 xff1a 将IP地址配置为静态的 xff0c 比如设固定IP地址为192 168 117 131 打开文件 etc sysconfig ne
  • 我的2014--众人皆醉我独醒

    转眼间大学两年过去了 xff0c 舍友们还在撸游戏 xff0c 有的也找到了另一半的归属 我是我宿舍唯一一个不玩电脑游戏的人 xff0c 当然 xff0c 不是不玩游戏就代表着成绩很好 xff0c 也不代表玩游戏就不好 xff0c 但意味着
  • Java多线程通信-利用传统的线程通信wait(),notify()方法实现“生产者消费者模式”

    想利用传统的线程通信wait notify xff0c notifyAll 方法 xff0c 必须依赖于同步监听器的存在 xff0c 也就是说 xff0c 对于synchronized修饰的同步方法 xff0c 因为该类的默认实例 xff0
  • java TCP/IP实现简单的多人聊天功能

    TCP IP是可靠的网络协议 xff0c 数据的传输需要服务端和客户端之间三次 握手 xff0c 比较适合文本等一些可靠性要求高的数据传输 xff0c 但是它的效率较UDP低 下面通过一张图来简要说明使用 ServerSocket 创建 T
  • 死锁面试题(什么是死锁,产生死锁的原因及必要条件)

    什么是死锁 xff1f 所谓死锁 xff0c 是指多个进程在运行过程中因争夺资源而造成的一种僵局 xff0c 当进程处于这种僵持状态时 xff0c 若无外力作用 xff0c 它们都将无法再向前推进 因此我们举个例子来描述 xff0c 如果此
  • 标准模板库-容器

    标准模板库STL Standard Template Libarary 是一个标准类与函数模板的库 STL包含容器 容器适配器 迭代器 算法 函数对象和函数适配器 容器 用来存储和组织其他对象的对象 T是存储在容器中的元素类型的模板类型形参
  • Ubuntu18.04安装PX4踩坑、报错及解决方案整理

    笔者最近需要跑无人机巡检大坝的仿真 xff0c 于是在自己的Ubuntu2018 04中开始安装PX4 xff0c 问过不少之前已经装过PX4的师兄和同学 xff0c 都曾在PX4安装过程中踩过许多坑 xff0c 耗费了不少时间 xff0c
  • 初识ROS文件结构:以阿木实验室Prometheus项目为例

    ROS的工作空间是一个存放工程开发相关文件的文件夹 xff0c Fuerte版本之后的ROS默认使用的是Catkin编译系统 功能包是ROS软件中的基本单元 xff0c 包含ROS节点 库 配置文件等 一个文件夹是功能包的标志是该文件夹中有
  • 六轴无人机装配问题小结(Pixhawk飞控、APM固件、电机装配、电调校准)

    笔者近期需要组装一架六轴无人机供超声波避障模块 单点激光雷达等传感器的测试使用 由于是第一次碰真机 xff0c 面对散落一箱的部件还是非常的头大的 xff0c 不过好在实验室有经验的大佬能提供一些指导 xff0c 并且还能够参考 创客智造
  • 测试API接口,返回404。

    报错 xff1a 34 timestamp 34 34 2020 06 02T12 40 53 125 43 00 00 34 34 status 34 404 34 error 34 34 Not Found 34 34 message
  • 再谈STM32的CAN过滤器-bxCAN的过滤器的4种工作模式以及使用方法总结

    转自 xff1a http blog csdn net flydream0 article details 52317532 1 前言 bxCAN是STM32系列最稳定的IP核之一 xff0c 无论有哪个新型号出来 xff0c 这个IP核基
  • NVIDIA TX2自制底板的USB口无法使用的一种解决方法

    这是由于官方的底板上采用INA3221芯片做了电源监控电路 xff0c 只有确保5V电源达到要求的情况下才会使能USB口 而自制的底板上将上述电路省略了 xff0c 所以导致了USB口无法使用 解决办法就是要给TX2更新设备树 在网上找到一

随机推荐

  • Benchmark(基准测试)初相识

    一 benchmark概念 在计算中 xff0c 基准是运行一个计算机程序 一组程序或其他操作的行为 xff0c 以评估一个对象的相对性能 xff0c 通常是通过对它运行一些标准测试和试验 基准测试一词也通常用于精心设计的基准测试程序本身
  • 嵌入式中的通讯协议——UART、I2C、SPI、DMA

    目录 一 通讯的基本概念 二 USART 串口通讯 三 I2C通讯协议 四 SPI通讯协议 五 DMA 直接存储器存取 六 USART I2C SPI比较 一 通讯的基本概念 1 串行通讯与并行通讯 xff08 按数据的传送方式 xff09
  • RISC与CISC比较

    RISC的设计重点在于降低由硬件执行指令的复杂度 xff0c 因为软件比硬件容易提供更大的灵活性和更高的智能 xff0c 因此RISC设计对编译器有更高的要求 xff1b CISC的设计则更侧重于硬件执行指令的功能 xff0c 使CISC的
  • 操作系统选择调度方式和算法的若干准则

    1 调度的类型 按调度的层次 xff1a 长期 xff08 长程 作业 高级 xff09 调度 xff1b 中期 xff08 中级 中程 xff09 调度 xff1b 短期 xff08 短程 进程 低级 xff09 调度 按OS 的类型 x
  • 提灯过桥问题

    题目 xff1a 小明一家过一座桥 xff0c 过桥时是黑夜 xff0c 所以必须有灯 现在小明过桥要1秒 xff0c 小明的弟弟要3秒 xff0c 小明的爸爸要6秒 xff0c 小明的妈妈要8秒 xff0c 小明的爷爷要12秒 每次此桥最
  • 如何判断一个整数数组中是否有重复元素

    题目 xff1a 写一个函数判断一个int类型的数组是否是有效的 所谓有效是指 xff1a 假设数组大小为n xff0c 那么这个int数组里的值为0 n 1之间的数 xff0c 并且每个数只能出现一次 xff0c 否则就是无效数组 例如
  • C++发送HTTP请求---亲测可行

    转自 xff1a http hi baidu com benbearlove item 1671c23017575825b3c0c53f 环境 xp sp3 vs2008 vs2010在静态库中使用 MFC include lt afxwi
  • 百度2014开发测试工程师笔试题(沈阳站)

    时间 xff1a 2013 9 21 地点 xff1a 沈阳 职位 xff1a 开发测试工程师
  • 2014百度校招开发测试工程师笔试题

    时间 xff1a 2013 9 28 地点 xff1a 深圳 职位 xff1a 开发测试工程师
  • 整体了解HADOOP框架及一些开源项目

    Hadoop框架中 xff0c 有很多优秀的工具 xff0c 帮助我们解决工作中的问题 Hadoop的位置 从上图可以看出 xff0c 越往右 xff0c 实时性越高 xff0c 越往上 xff0c 涉及到算法等越多 越往上 xff0c 越
  • Kafka简介

    Kafka简介 在当前的大数据时代 xff0c 第一个挑战是海量数据的收集 xff0c 另一个就是这些数据的分析 数据分析的类型通常有用户行为数据 应用性能跟踪数据 活动数据日志 事件消息等 消息发布机制用于连接各种应用并在它们之间路由消息
  • Flume入门笔记------架构以及应用介绍

    在具体介绍本文内容之前 xff0c 先给大家看一下Hadoop业务的整体开发流程 xff1a 从Hadoop的业务开发流程图中可以看出 xff0c 在大数据的业务处理过程中 xff0c 对于数据的采集是十分重要的一步 xff0c 也是不可避
  • 分布式服务框架dubbo原理解析

    alibaba有好几个分布式框架 xff0c 主要有 xff1a 进行远程调用 类似于RMI的这种远程调用 的 dubbo hsf xff0c jms消息服务 napoli notify xff0c KV数据库 tair 等 这个框架 工具
  • Linux下安装ElasticSearch

    Linux下安装ElasticSearch 一 下载 amp 安装二 安装中遇到的问题及解决方案三 使用中遇到的问题及解决方案四 安装head五 安装kibana 一 下载 amp 安装 先安装JDK 下载elasticsearch 7 0
  • cmake学习1:基本的CMakeLists的编写

    前言 自己在使用cmake进行编译工程的时候不太了解cmake的基本使用方法 有时候出现找不到第三方库的问题也不知如何排查 因此相对cmake有个稍微系统的认识 希望能用这个强大的工具来更好的为自己的工程服务 因此总结为了几篇博客 主要参考
  • ZooKeeper 报错 ERROR [main:ZooKeeperServerMain@64] 的解决办法

    myid span class hljs type ERROR span main span class hljs type ZooKeeperServerMain span 64 span class hljs number 64 spa
  • Ubuntu14.04下安装cmake 3.9.6

    简述 xff1a CMake是一个跨平台 的编译自动配置 工具 xff0c 它使用一个名为CMakeLists txt 的文件来描述构建过程 xff0c 可以产生标准的构建文件 它可以用简单的语句来描述所有平台的安装 编译过程 它能够输出各
  • 二维数组功能测试,超详细

    include lt stdio h gt int main char buf 2 5 61 39 a 39 39 b 39 39 c 39 39 d 39 39 e 39 39 f 39 39 g 39 39 h 39 39 i 39 3
  • Cmake知识----编写CMakeLists.txt文件编译C/C++程序

    简述 xff1a CMake是一个跨平台的安装 编译 工具 可以用简单的语句来描述所有平台的安装 编译过程 他能够输出各种各样的makefile或者project文件 能测试编译器所支持的C 43 43 特性 类似UNIX下的automak
  • 知识点总结:Java核心技术(卷1)

    Java核心技术 xff08 卷1 xff09 一 基础概念 1 1 基本程序设计结构 1 1 数据类型 1 1 1 数值类型 1 从java7开始 xff0c 加上前缀0b或0B就可以写二进制 xff1b 2 指数的表示 十进制中以10为