• [技术干货] Java - lambda 表达式入门
    概述Lambda表达式,也可称为闭包,是JDK8的新特性。Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中),可以使代码变的更加简洁紧凑。Lambda表达式是一个可传递的代码块,可以在以后执行一次或多次。名字起源是以前还没有计算机时,逻辑学家Alonzo Church想要形式化的表示能有效计算的数学函数,使用了希腊字母lambda(λ \lambdaλ)来标记参数,从那以后,带参数变量的表达式就被称为lambda表达式。lambda表达式本质是一个匿名函数,比如以下函数public int add(int x, int y) { return x + y; }可以转换为:(int x, int y) -> x + y;语法语法格式如下(parameters) -> expression或(parameters) ->{ statements; }其中()用来描述参数列表,{}用来描述方法体,->是lambda运算符,读作goes to。可以包含显示的return语句,如:(String sirst,String second)-> { if(first.length()<second.length())return -1; else if(first.length()>second.length())return 1; else return 0; }可以没有参数,但()不可缺省:()->{for(int i=0;i<10;i++)System.out.print(i);}如果可以推导出参数类型,则可以忽略其类型:Comparator<String>cmp=(first,second)->first.length()-second.length();特别注意不能只在某些分支返回一个值,这是不合法的,如:(int x)->{if(x>=0)return 1;}常用示例:ArrayList<Integer>list=new ArrayList<>(); Collections.addAll(list,1,2,3,4,5); //遍历 list.forEach(e->{System.out.println(e);}); //删除指定值 list.removeIf(e->e==3); //排序 list.sort((o1,o2)->o2-o1); //遍历(双冒号操作符) list.forEach(System.out::println);函数式接口Java中又很多封装代码块的接口,如ActionListener、Comparator等,lambda表达式与这些接口时兼容的。对于只有一个抽象方法的接口,需要这种接口的对象时,就可以提供一个lambda表达式,这种接口称为函数式接口。比如Arrays.sort()方法,它的第二个参数需要一个Comparator实例,而Comparator就是只有一个方法的接口,所以可以使用lambda表达式替代,可以把lambda表达式看作一个函数,而不是一个对象,如:Arrays.sort(arrays, (first,second)->first.length()-second.length());lambda表达式还可以转换为接口,比如实现Runnable接口:new Thread(() -> System.out.println("记得一键三连")).start(); Runnable r = () -> System.out.println("(。・∀・)ノ"); r.run();再如之前提到的removeIf()方法,它的参数就是一个Predicate接口(位于java.util.function包),这个接口专门用来传递lambda表达式,如删除一个数组列表所有null值:list.removeIf(e->e==null)方法引用当在Lambda表达式中直接调用了一个方法时可以使用,其写法为目标引用::方法名称。有时候,可能已经有现成的方法可以完成你想要传递到其他代码的某个动作,如遍历打印集合:list.forEach(e->{System.out.println(e);});我们可以直接把现成的println方法传递给它:list.forEach(System.out::println);它们是等价的,是一个方法引用的写法。再如对字符串排序而不考虑大小写,可以直接传递以下方法表达式:Arrays.sort(strings,String::compareToIgnoreCase);也就是说使用双冒号操作符::来分离方法名与对象或类名:object::instanceMethodClass::staticMethodClass::instanceMethod对于前两种情况,方法引用等价于提供方法参数的lambda表达式,如Math::Pow 等价于 (x,y) -> Math.pos(x,y) 对于第三种情况,第一个参数会成为方法的目标,如String::compareToIgnoreCase 等同于 (x,y) -> x.compareToIgnoreCase(y) 也可以在方法中引用this参数,如this::equals等价于x->this.equals(x),同样的,使用super也是允许的。构造器引用构造器引用与方法引用很类似,只不过方法名为new,例如Person::new是Person类构造器的一个引用,如果有多个构造器,编译器会取决于上下文。比如有一个字符串列表,可以把他转换为一个Person对象数组,为此要在各个字符串上调用构造器。可以用数组类型建立构造器引用,如int[]::new是一个构造器引用,它有一个参数即数组长度,等价于lambda表达式:x->new int[x];在Java中无法构造泛型类型T的数组,而数组构造器引用就可克服这个限制。如表达式new T[n]会产生错误,因为这会改为new Object[n]。设我们需要一个Person对象数组,Stream接口有一个toArray方法可以返回Object数组:Object[] people=stream.toArray();以上得到的是一个Object引用数组,可以把Person[]::new传入给toArray()方法,从而得到一个Person对象数组:Object[] people=stream.toArray(Person[]::new);变量作用域有时候,我们希望能够在lambda表达式中访问外围方法或类中的变量,如下面例子:public static void printTip(String text) { Runnable r = () -> System.out.println(text); r.run(); } public static void main(String[] args) { String text="一键三连"; printTip(text); }现在来看lambda表达式中的text变量,它并不是在这个lambda表达式中定义的,实际上是printTip方法的一个参数变量。但仔细想想,lambda表达式的代码可能会在printTip调用返回很久以后才运行,而那时这个参数变量已经不存在了,如何保留text变量?首先巩固瞎lambda表达式的理解,lmabda表达式有3个部分:一个代码块、变量、自由变量的值(指非参数而且不在代码中定义的变量)。在上面的例子中,lambda表达式有一个自由变量text,表示lambda表达式的数据结构必须存储的值(这里的字符串“一键三连”),我们称它被lambda表达式捕获(captured)。关于代码块和自由变量值有一个术语:闭包(closure),在Java中,lambda表达式就是闭包。lambda表达式捕获变量必须遵循的规则:捕获的变量必须实际上必须是最终变量(effectively final),最终变量是指这个变量初始化之后就不会再为它赋新值,即在lambda表达式内外都不能在修改值。如lambda内修改:public static void printTip(String text) { Runnable r = () -> { System.out.println(text); text="修改值会报错"; }; r.run(); } public static void main(String[] args) { String text="一键三连"; printTip(text); }lambda外修改:public static void main(String[] args) { for(int i=0;i<5;i++){ //表达式外修改变量i报错 Runnable r = () -> System.out.println(i); r.run(); } }此外,在方法中不能有同名的局部变量,lambda表达式也是如此:public static void main(String[] args) { int first=666; //同名会报错 Comparator<String> cmp= (first,second)->first.length()-second.length(); }对于lambda表达式中使用this关键字时,是指创建这个lambda表达式的方法饿this参数。处理lambda表达式使用lambda表达式的重点是延迟执行(deferred execution)。如果要立即执行代码的画完全可以直接执行而无需放到一个lambda表达式中,之所以希望以后在执行代码,这有很多原因,如:在一个单独的线程中运行代码多次运行代码在算法的适当位置运行代码发生某种情况时执行代码只有在必要时才运行代码设想要重复一个动作n次,将这个动作和重复次数,传递到一个repeat方法,要接受这个lambda表达式需要选择一个函数式接口,在这里我们可以使用Runnable接口,后面给出Java API中提供的最重要的函数式接口。public static void repeat(int n,Runnable action){ for(int i=0;i<n;i++) action.run(); } public static void main(String[] args) { repeat(10,()-> System.out.println("一键三连")); } 函数式接口 参数类型 返回类型 抽象方法名 描述 其他方法 ---------------------------------------------------------------------------------------- Runnable 无 void run 作为无参数或返回值的动作执行 Supplier<T> 无 T get 提供一个T类型的值 Consumer<T> T void accept 处理一个T类型的值 addThen BiConsumer<T,U> T,U void accept 处理T和U类型的值 addThen Function<T,R> T R apply 有一个T类型参数的函数 compose,addThen,idenity BiFunction<T,U,R> T,U R apply 有T和U类型参数的函数 addThen UnaryOperator<T> T T apply 类型T上的一元操作符 compose,addThen,identity BinaryOperator<T> T,T T apply 类型T上的二元操作符 addThen,maxBy,minBy PreDicate<T> T boolean test 布尔值函数 add,or,negate,isEqual BiPredicate T,U boolean test 有两个参数的布尔值函数 add,or,negate现在让这个例子更复杂一些,我们希望知道这个动作出现在哪一次迭代中。为此需要选择一个合适的函数式接口,其中要包含一个方法,这个方法有一个int参数而且返回类型为void,如下所示:public interface IntConsumer{ void accept(int value); } public static void repeat(int n,IntConsumer action){ for(int i=0;i<n;i++) action.accept(i); } public static void main(String[] args) { repeat(10,i-> System.out.println(9-i)); }下表列出了基本类型int、long和double的34个可能的规范,最好使用这些特殊化规范来减少自动装箱:函数式接口 参数类型 返回类型 抽象方法名 ---------------------------------------------------------- BooleanSupplier none boolean getAsBoolean P PPSupplier none p pp getAsP PP P PPConsumer p pp void accept ObjP PPConsumer<T> T,p pp void accept P PPFunction<T> p pp T apply P PPToQFunction p pp q qq applyAsQ QQ ToP PPFunction<T> T p pp applyAsP PP ToP PPBiFunction<T,U> T,U p pp applyAsP PP P PPUnaryOperator p pp p pp applyAsP PP P PPBinaryOperator p pp,p pp p pp applyAsP PP P PPPredicate p pp boolean testp pp,q qq为int,long,double;P PP,Q QQ为Int,Long,Double。————————————————
  • [技术干货] String StringBuffer StringBuilder 的区别
    1、String  String:字符串常量,字符串长度不可变。Java中String是immutable(不可变)的。  String类的包含如下定义:[java] view plaincopy /** The value is used for character storage. */ private final char value[]; /** The offset is the first index of the storage that is used. */ private final int offset; /** The count is the number of characters in the String. */ private final int count;   用于存放字符的数组被声明为final的,因此只能赋值一次,不可再更改。 2、StringBuffer(JDK1.0)  StringBuffer:字符串变量(Synchronized,即线程安全)。如果要频繁对字符串内容进行修改,出于效率考虑最好使用StringBuffer,如果想转成String类型,可以调用StringBuffer的toString()方法。  Java.lang.StringBuffer线程安全的可变字符序列。在任意时间点上它都包含某种特定的字符序列,但通过某些方法调用可以改变该序列的长度和内容。可将字符串缓冲区安全地用于多个线程。  StringBuffer 上的主要操作是 append 和 insert 方法,可重载这些方法,以接受任意类型的数据。每个方法都能有效地将给定的数据转换成字符串,然后将该字符串的字符追加或插入到字符串缓冲区中。append 方法始终将这些字符添加到缓冲区的末端;而 insert 方法则在指定的点添加字符。例如,如果 z 引用一个当前内容是“start”的字符串缓冲区对象,则此方法调用 z.append("le") 会使字符串缓冲区包含“startle”,而 z.insert(4, "le") 将更改字符串缓冲区,使之包含“starlet”。3、StringBuilder(JDK5.0)  StringBuilder:字符串变量(非线程安全)。在内部,StringBuilder对象被当作是一个包含字符序列的变长数组。  java.lang.StringBuilder是一个可变的字符序列,是JDK5.0新增的。此类提供一个与 StringBuffer 兼容的 API,但不保证同步。该类被设计用作 StringBuffer 的一个简易替换,用在字符串缓冲区被单个线程使用的时候(这种情况很普遍)。  其构造方法如下:构造方法描述StringBuilder()创建一个容量为16的StringBuilder对象(16个空元素)StringBuilder(CharSequence cs)创建一个包含cs的StringBuilder对象,末尾附加16个空元素StringBuilder(int initCapacity)创建一个容量为initCapacity的StringBuilder对象StringBuilder(String s)创建一个包含s的StringBuilder对象,末尾附加16个空元素  在大部分情况下,StringBuilder > StringBuffer。这主要是由于前者不需要考虑线程安全。4、三者区别  String 类型和StringBuffer的主要性能区别:String是不可变的对象, 因此在每次对String 类型进行改变的时候,都会生成一个新的 String 对象,然后将指针指向新的 String 对象,所以经常改变内容的字符串最好不要用 String ,因为每次生成对象都会对系统性能产生影响,特别当内存中无引用对象多了以后, JVM 的 GC 就会开始工作,性能就会降低。  使用 StringBuffer 类时,每次都会对 StringBuffer 对象本身进行操作,而不是生成新的对象并改变对象引用。所以多数情况下推荐使用 StringBuffer ,特别是字符串对象经常改变的情况下。  在某些特别情况下, String 对象的字符串拼接其实是被 Java Compiler 编译成了 StringBuffer 对象的拼接,所以这些时候 String 对象的速度并不会比 StringBuffer 对象慢,例如:[java] view plaincopy String s1 = “This is only a” + “ simple” + “ test”; StringBuffer Sb = new StringBuilder(“This is only a”).append(“ simple”).append(“ test”);   生成 String s1对象的速度并不比 StringBuffer慢。其实在Java Compiler里,自动做了如下转换:  Java Compiler直接把上述第一条语句编译为:  [java] view plaincopy String s1 = “This is only a simple test”;   所以速度很快。但要注意的是,如果拼接的字符串来自另外的String对象的话,Java Compiler就不会自动转换了,速度也就没那么快了,例如:[java] view plaincopy String s2 = “This is only a”; String s3 = “ simple”; String s4 = “ test”; String s1 = s2 + s3 + s4;   这时候,Java Compiler会规规矩矩的按照原来的方式去做,String的concatenation(即+)操作利用了StringBuilder(或StringBuffer)的append方法实现,此时,对于上述情况,若s2,s3,s4采用String定义,拼接时需要额外创建一个StringBuffer(或StringBuilder),之后将StringBuffer转换为String;若采用StringBuffer(或StringBuilder),则不需额外创建StringBuffer。5、使用策略(1)基本原则:如果要操作少量的数据,用String ;单线程操作大量数据,用StringBuilder ;多线程操作大量数据,用StringBuffer。(2)不要使用String类的"+"来进行频繁的拼接,因为那样的性能极差的,应该使用StringBuffer或StringBuilder类,这在Java的优化上是一条比较重要的原则。例如:[java] view plaincopy String result = ""; for (String s : hugeArray) { result = result + s; } // 使用StringBuilder StringBuilder sb = new StringBuilder(); for (String s : hugeArray) { sb.append(s); } String result = sb.toString();   当出现上面的情况时,显然我们要采用第二种方法,因为第一种方法,每次循环都会创建一个String result用于保存结果,除此之外二者基本相同(对于jdk1.5及之后版本)。  (3)为了获得更好的性能,在构造 StirngBuffer 或 StirngBuilder 时应尽可能指定它们的容量。当然,如果你操作的字符串长度(length)不超过 16 个字符就不用了,当不指定容量(capacity)时默认构造一个容量为16的对象。不指定容量会显著降低性能。(4)StringBuilder一般使用在方法内部来完成类似"+"功能,因为是线程不安全的,所以用完以后可以丢弃。StringBuffer主要用在全局变量中。(5)相同情况下使用 StirngBuilder 相比使用 StringBuffer 仅能获得 10%~15% 左右的性能提升,但却要冒多线程不安全的风险。而在现实的模块化编程中,负责某一模块的程序员不一定能清晰地判断该模块是否会放入多线程的环境中运行,因此:除非确定系统的瓶颈是在 StringBuffer 上,并且确定你的模块不会运行在多线程模式下,才可以采用StringBuilder;否则还是用StringBuffer。————————————————
  • [全栈开发者] 【Java编程创造营】Java相关微认证打卡贴
    为了巩固大家的学习成果,紧跟学习进度请将需要完成的相关微认证考核按要求回复到本帖下方按要求格式回复即可获得积分累计阶段奖品,还能有机会获得附加幸运奖哦~征集时间课程全阶段微认证考核要求提交微认证证书截图 阶段考核+30分通过特定场景化学习和实际操作,可以获得华为云微认证提供的具有【华为云官方微认证证书】Java编程创造营使用以下场景参与认证考核华为企业级JAVA编程规范认证链接:https://edu.huaweicloud.com/certifications/9eeea7c524514eb58ebc169186813cf4参与认证的同学请将【微认证订单截图&微认证证书截图+华为云ID】回复到本帖当中 才能算作最终考核成功,考核分数才能统计回帖示例:活动注意事项1. 学习任务提交后,小助手会在本阶段学习周期内,按序完成审核,并增加活动积分;2. 本次活动通过完成微认证任务,可获得的积分上限为30分;3. 请务必按照上述要求提交内容,以免影响积分增加;4. 若积分值相同则以完成学习任务的时间先后排序,其中任务完成时间的判定优先级为:相关微认证>阶段沙箱实验>每周学习笔记>问答官排位赛>每章随堂测验打卡5. 其他积分获取方式请查看活动社群公告。想了解更多关于课程内容请移步主帖:https://bbs.huaweicloud.com/forum/forum.php?mod=viewthread&tid=125761
  • [技术干货] Java 常见经典问答题
    1.什么是Java虚拟机?为什么Java被称作是“平台无关的编程语言”?Java虚拟机是一个可以执行Java字节码的虚拟机进程。Java源文件被编译成能被Java虚拟机执行的字节码文件。Java被设计成允许应用程序可以运行在任意的平台,而不需要程序员为每一个平台单独重写或者是重新编译。Java虚拟机让这个变为可能,因为它知道底层硬件平台的指令长度和其他特性。2.JDK和JRE的区别是什么?Java运行时环境(JRE)是将要执行Java程序的Java虚拟机。它同时也包含了执行applet需要的浏览器插件。Java开发工具包(JDK)是完整的Java软件开发包,包含了JRE,编译器和其他的工具(比如:JavaDoc,Java调试器),可以让开发者开发、编译、执行Java应用程序。3.”static”关键字是什么意思?Java中是否可以覆盖(override)一个private或者是static的方法?“static”关键字表明一个成员变量或者是成员方法可以在没有所属的类的实例变量的情况下被访问。Java中static方法不能被覆盖,因为方法覆盖是基于运行时动态绑定的,而static方法是编译时静态绑定的。static方法跟类的任何实例都不相关,所以概念上不适用。4.是否可以在static环境中访问非static变量?static变量在Java中是属于类的,它在所有的实例中的值是一样的。当类被Java虚拟机载入的时候,会对static变量进行初始化。如果你的代码尝试不用实例来访问非static的变量,编译器会报错,因为这些变量还没有被创建出来,还没有跟任何实例关联上。5.Java支持的数据类型有哪些?什么是自动拆装箱?Java语言支持的8种基本数据类型是:byteshortintlongfloatdoublebooleanchar自动装箱是Java编译器在基本数据类型和对应的对象包装类型之间做的一个转化。比如:把int转化成Integer,double转化成Double,等等。反之就是自动拆箱。6.Java中的方法覆盖(Overriding)和方法重载(Overloading)是什么意思?Java中的方法重载发生在同一个类里面两个或者是多个方法的方法名相同但是参数不同的情况。与此相对,方法覆盖是说子类重新定义了父类的方法。方法覆盖必须有相同的方法名,参数列表和返回类型。覆盖者可能不会限制它所覆盖的方法的访问。7.Java中,什么是构造函数?什么是构造函数重载?什么是复制构造函数?当新对象被创建的时候,构造函数会被调用。每一个类都有构造函数。在程序员没有给类提供构造函数的情况下,Java编译器会为这个类创建一个默认的构造函数。Java中构造函数重载和方法重载很相似。可以为一个类创建多个构造函数。每一个构造函数必须有它自己唯一的参数列表。Java不支持像C++中那样的复制构造函数,这个不同点是因为如果你不自己写构造函数的情况下,Java不会创建默认的复制构造函数。8.Java支持多继承么?Java中类不支持多继承,只支持单继承(即一个类只有一个父类)。 但是java中的接口支持多继承,,即一个子接口可以有多个父接口。(接口的作用是用来扩展对象的功能,一个子接口继承多个父接口,说明子接口扩展了多个功能,当类实现接口时,类就扩展了相应的功能)。9.接口和抽象类的区别是什么?Java提供和支持创建抽象类和接口。它们的实现有共同点,不同点在于:接口中所有的方法隐含的都是抽象的。而抽象类则可以同时包含抽象和非抽象的方法。类可以实现很多个接口,但是只能继承一个抽象类类可以不实现抽象类和接口声明的所有方法,当然,在这种情况下,类也必须得声明成是抽象的。抽象类可以在不提供接口方法实现的情况下实现接口。Java接口中声明的变量默认都是final的。抽象类可以包含非final的变量。Java接口中的成员函数默认是public的。抽象类的成员函数可以是private,protected或者是public。接口是绝对抽象的,不可以被实例化。抽象类也不可以被实例化,但是,如果它包含main方法的话是可以被调用的。也可以参考JDK8中抽象类和接口的区别10.什么是值传递和引用传递?值传递是对基本型变量而言的,传递的是该变量的一个副本,改变副本不影响原变量.引用传递一般是对于对象型变量而言的,传递的是该对象地址的一个副本, 并不是原对象本身 。 所以对引用对象进行操作会同时改变原对象.一般认为,java内的传递都是值传递.11.进程和线程的区别是什么?进程是执行着的应用程序,而线程是进程内部的一个执行序列。一个进程可以有多个线程。线程又叫做轻量级进程。12.创建线程有几种不同的方式?你喜欢哪一种?为什么?有三种方式可以用来创建线程:继承Thread类实现Runnable接口应用程序可以使用Executor框架来创建线程池实现Runnable接口这种方式更受欢迎,因为这不需要继承Thread类。在应用设计中已经继承了别的对象的情况下,这需要多继承(而Java不支持多继承),只能实现接口。同时,线程池也是非常高效的,很容易实现和使用。13.概括的解释下线程的几种可用状态。1. 新建( new ):新创建了一个线程对象。2. 可运行( runnable ):线程对象创建后,其他线程(比如 main 线程)调用了该对象 的 start ()方法。该状态的线程位于可运行线程池中,等待被线程调度选中,获 取 cpu 的使用权 。3. 运行( running ):可运行状态( runnable )的线程获得了 cpu 时间片( timeslice ) ,执行程序代码。4. 阻塞( block ):阻塞状态是指线程因为某种原因放弃了 cpu 使用权,也即让出了 cpu timeslice ,暂时停止运行。直到线程进入可运行( runnable )状态,才有 机会再次获得 cpu timeslice 转到运行( running )状态。阻塞的情况分三种:(一). 等待阻塞:运行( running )的线程执行 o . wait ()方法, JVM 会把该线程放 入等待队列( waitting queue )中。(二). 同步阻塞:运行( running )的线程在获取对象的同步锁时,若该同步锁 被别的线程占用,则 JVM 会把该线程放入锁池( lock pool )中。(三). 其他阻塞: 运行( running )的线程执行 Thread . sleep ( long ms )或 t . join ()方法,或者发出了 I / O 请求时, JVM 会把该线程置为阻塞状态。 当 sleep ()状态超时、 join ()等待线程终止或者超时、或者 I / O 处理完毕时,线程重新转入可运行( runnable )状态。5. 死亡( dead ):线程 run ()、 main () 方法执行结束,或者因异常退出了 run ()方法,则该线程结束生命周期。死亡的线程不可再次复生。14.同步方法和同步代码块的区别是什么?区别:同步方法默认用this或者当前类class对象作为锁;同步代码块可以选择以什么来加锁,比同步方法要更细颗粒度,我们可以选择只同步会发生同步问题的部分代码而不是整个方法;15.在监视器(Monitor)内部,是如何做线程同步的?程序应该做哪种级别的同步?监视器和锁在Java虚拟机中是一块使用的。监视器监视一块同步代码块,确保一次只有一个线程执行同步代码块。每一个监视器都和一个对象引用相关联。线程在获取锁之前不允许执行同步代码。16.什么是死锁(deadlock)?两个线程或两个以上线程都在等待对方执行完毕才能继续往下执行的时候就发生了死锁。结果就是这些线程都陷入了无限的等待中。17.如何确保N个线程可以访问N个资源同时又不导致死锁?使用多线程的时候,一种非常简单的避免死锁的方式就是:指定获取锁的顺序,并强制线程按照指定的顺序获取锁。因此,如果所有的线程都是以同样的顺序加锁和释放锁,就不会出现死锁了。18.Java集合类框架的基本接口有哪些?集合类接口指定了一组叫做元素的对象。集合类接口的每一种具体的实现类都可以选择以它自己的方式对元素进行保存和排序。有的集合类允许重复的键,有些不允许。Java集合类提供了一套设计良好的支持对一组对象进行操作的接口和类。Java集合类里面最基本的接口有:Collection:代表一组对象,每一个对象都是它的子元素。Set:不包含重复元素的Collection。List:有顺序的collection,并且可以包含重复元素。Map:可以把键(key)映射到值(value)的对象,键不能重复。19.为什么集合类没有实现Cloneable和Serializable接口?克隆(cloning)或者是序列化(serialization)的语义和含义是跟具体的实现相关的。因此,应该由集合类的具体实现来决定如何被克隆或者是序列化。20.什么是迭代器(Iterator)?Iterator接口提供了很多对集合元素进行迭代的方法。每一个集合类都包含了可以返回迭代器实例的迭代方法。迭代器可以在迭代的过程中删除底层集合的元素,但是不可以直接调用集合的remove(Object Obj)删除,可以通过迭代器的remove()方法删除。21.Iterator和ListIterator的区别是什么?下面列出了他们的区别:Iterator可用来遍历Set和List集合,但是ListIterator只能用来遍历List。Iterator对集合只能是前向遍历,ListIterator既可以前向也可以后向。ListIterator实现了Iterator接口,并包含其他的功能,比如:增加元素,替换元素,获取前一个和后一个元素的索引,等等。22.快速失败(fail-fast)和安全失败(fail-safe)的区别是什么?Iterator的安全失败是基于对底层集合做拷贝,因此,它不受源集合上修改的影响。java.util包下面的所有的集合类都是快速失败的,而java.util.concurrent包下面的所有的类都是安全失败的。快速失败的迭代器会抛出ConcurrentModificationException异常,而安全失败的迭代器永远不会抛出这样的异常。23.Java中的HashMap的工作原理是什么?Java中的HashMap是以键值对(key-value)的形式存储元素的。HashMap需要一个hash函数,它使用hashCode()和equals()方法来向集合/从集合添加和检索元素。当调用put()方法的时候,HashMap会计算key的hash值,然后把键值对存储在集合中合适的索引上。如果key已经存在了,value会被更新成新值。HashMap的一些重要的特性是它的容量(capacity),负载因子(load factor)和扩容极限(threshold resizing)。24.hashCode()和equals()方法的重要性体现在什么地方?Java中的HashMap使用hashCode()和equals()方法来确定键值对的索引,当根据键获取值的时候也会用到这两个方法。如果没有正确的实现这两个方法,两个不同的键可能会有相同的hash值,因此,可能会被集合认为是相等的。而且,这两个方法也用来发现重复元素。所以这两个方法的实现对HashMap的精确性和正确性是至关重要的。25.HashMap和Hashtable有什么区别?HashMap和Hashtable都实现了Map接口,因此很多特性非常相似。但是,他们有以下不同点:HashMap允许键和值是null,而Hashtable不允许键或者值是null。Hashtable是同步的,而HashMap不是。因此,HashMap更适合于单线程环境,而Hashtable适合于多线程环境。HashMap提供了可供应用迭代的键的集合,因此,HashMap是快速失败的。另一方面,Hashtable提供了对键的列举(Enumeration)。一般认为Hashtable是一个遗留的类。26.数组(Array)和列表(ArrayList)有什么区别?什么时候应该使用Array而不是ArrayList?下面列出了Array和ArrayList的不同点:Array可以包含基本类型和对象类型,ArrayList只能包含对象类型。Array大小是固定的,ArrayList的大小是动态变化的。ArrayList提供了更多的方法和特性,比如:addAll(),removeAll(),iterator()等等。对于基本类型数据,集合使用自动装箱来减少编码工作量。但是,当处理固定大小的基本数据类型的时候,这种方式相对比较慢。数组适合于存储元素个数不变的数据,如果元素的个数是变化的,用ArrayList更好27.ArrayList和LinkedList有什么区别?ArrayList和LinkedList都实现了List接口,他们有以下的不同点:ArrayList是基于索引的数据接口,它的底层是数组。它可以以O(1)时间复杂度对元素进行随机访问。与此对应,LinkedList是以元素列表的形式存储它的数据,每一个元素都和它的前一个和后一个元素链接在一起,在这种情况下,查找某个元素的时间复杂度是O(n)。相对于ArrayList,LinkedList的插入,添加,删除操作速度更快,因为当元素被添加到集合任意位置的时候,不需要像数组那样重新计算大小或者是更新索引。LinkedList比ArrayList更占内存,因为LinkedList为每一个节点存储了两个引用,一个指向前一个元素,一个指向下一个元素。28.Comparable和Comparator接口是干什么的?列出它们的区别。Java提供了只包含一个compareTo()方法的Comparable接口。这个方法可以个给两个对象排序。具体来说,它返回负数,0,正数来表明已经存在的对象小于,等于,大于输入对象。Java提供了包含compare()和equals()两个方法的Comparator接口。compare()方法用来给两个输入参数排序,返回负数,0,正数表明第一个参数是小于,等于,大于第二个参数。equals()方法需要一个对象作为参数,它用来决定输入参数是否和comparator相等。只有当输入参数也是一个comparator并且输入参数和当前comparator的排序结果是相同的时候,这个方法才返回true。29.什么是Java优先级队列(Priority Queue)?PriorityQueue是一个基于优先级堆的无界队列,它的元素是按照自然顺序(natural order)排序的。在创建的时候,我们可以给它提供一个负责给元素排序的比较器。PriorityQueue不允许null值,因为他们没有自然顺序,或者说他们没有任何的相关联的比较器。最后,PriorityQueue不是线程安全的,入队和出队的时间复杂度是O(log(n))。30.你了解大O符号(big-O notation)么?你能给出不同数据结构的例子么?大O符号描述了当数据结构里面的元素增加的时候,算法的规模或者是性能在最坏的场景下有多么好。大O符号也可用来描述其他的行为,比如:内存消耗。因为集合类实际上是数据结构,我们一般使用大O符号基于时间,内存和性能来选择最好的实现。大O符号可以对大量数据的性能给出一个很好的说明。31.如何权衡是使用无序的数组还是有序的数组?有序数组最大的好处在于查找的时间复杂度是O(log n),而无序数组是O(n)。有序数组的缺点是插入操作的时间复杂度是O(n),因为值大的元素需要往后移动来给新元素腾位置。相反,无序数组的插入时间复杂度是常量O(1)。32.Java集合类框架的最佳实践有哪些?根据应用的需要正确选择要使用的集合的类型对性能非常重要,比如:假如元素的大小是固定的,而且能事先知道,我们就应该用Array而不是ArrayList。有些集合类允许指定初始容量。因此,如果我们能估计出存储的元素的数目,我们可以设置初始容量来避免重新计算hash值或者是扩容。为了类型安全,可读性和健壮性的原因总是要使用泛型。同时,使用泛型还可以避免运行时的ClassCastException。使用JDK提供的不变类(immutable class)作为Map的键可以避免为我们自己的类实现hashCode()和equals()方法。编程的时候接口优于实现。底层的集合实际上是空的情况下,返回长度是0的集合或者是数组,不要返回null。33.Enumeration接口和Iterator接口的区别有哪些?Enumeration速度是Iterator的2倍,同时占用更少的内存。但是,Iterator远远比Enumeration安全,因为其他线程不能够修改正在被iterator遍历的集合里面的对象。同时,Iterator允许调用者删除底层集合里面的元素,这对Enumeration来说是不可能的。34.HashSet和TreeSet有什么区别?HashSet是由一个hash表来实现的,因此,它的元素是无序的。add(),remove(),contains()方法的时间复杂度是O(1)。另一方面,TreeSet是由一个树形的结构来实现的,它里面的元素是有序的。因此,add(),remove(),contains()方法的时间复杂度是O(logn)。35.Java中垃圾回收有什么目的?什么时候进行垃圾回收?垃圾回收的目的是识别并且丢弃应用不再使用的对象来释放和重用资源。36.System.gc()和Runtime.gc()会做什么事情?这两个方法用来提示JVM要进行垃圾回收。但是,立即开始还是延迟进行垃圾回收是取决于JVM的。37.finalize()方法什么时候被调用?垃圾回收器(garbage colector)决定回收某对象时,就会运行该对象的finalize()方法 但是在Java中很不幸,如果内存总是充足的,那么垃圾回收可能永远不会进行,也就是说filalize()可能永远不被执行,显然指望它做收尾工作是靠不住的。 那么finalize()究竟是做什么的呢?它最主要的用途是回收特殊渠道申请的内存。Java程序有垃圾回收器,所以一般情况下内存问题不用程序员操心。但有一种JNI(Java Native Interface)调用non-Java程序(C或C++),finalize()的工作就是回收这部分的内存。38.如果对象的引用被置为null,垃圾收集器是否会立即释放对象占用的内存?不会,在下一个垃圾回收周期中,这个对象将是可被回收的。39.Java堆的结构是什么样子的?什么是堆中的永久代(Perm Gen space)?JVM的堆是运行时数据区,所有类的实例和数组都是在堆上分配内存。它在JVM启动的时候被创建。对象所占的堆内存是由自动内存管理系统也就是垃圾收集器回收。堆内存是由存活和死亡的对象组成的。存活的对象是应用可以访问的,不会被垃圾回收。死亡的对象是应用不可访问尚且还没有被垃圾收集器回收掉的对象。一直到垃圾收集器把这些对象回收掉之前,他们会一直占据堆内存空间。永久代是用于存放静态文件,如Java类、方法等。持久代对垃圾回收没有显著影响,但是有些应用可能动态生成或者调用一些class,例如Hibernate 等,在这种时候需要设置一个比较大的持久代空间来存放这些运行过程中新增的类,永久代中一般包含:类的方法(字节码…)类名(Sring对象).class文件读到的常量信息class对象相关的对象列表和类型列表 (e.g., 方法对象的array).JVM创建的内部对象JIT编译器优化用的信息40.串行(serial)收集器和吞吐量(throughput)收集器的区别是什么?吞吐量收集器使用并行版本的新生代垃圾收集器,它用于中等规模和大规模数据的应用程序。而串行收集器对大多数的小应用(在现代处理器上需要大概100M左右的内存)就足够了。41.在Java中,对象什么时候可以被垃圾回收?当对象对当前使用这个对象的应用程序变得不可触及的时候,这个对象就可以被回收了。42.JVM的永久代中会发生垃圾回收么?垃圾回收不会发生在永久代,如果永久代满了或者是超过了临界值,会触发完全垃圾回收(Full GC)。如果你仔细查看垃圾收集器的输出信息,就会发现永久代也是被回收的。这就是为什么正确的永久代大小对避免Full GC是非常重要的原因。43.Java中的两种异常类型是什么?他们有什么区别?Java中有两种异常:受检查的(checked)异常和不受检查的(unchecked)异常。不受检查的异常不需要在方法或者是构造函数上声明,就算方法或者是构造函数的执行可能会抛出这样的异常,并且不受检查的异常可以传播到方法或者是构造函数的外面。相反,受检查的异常必须要用throws语句在方法或者是构造函数上声明。44.Java中Exception和Error有什么区别?Exception和Error都是Throwable的子类。Exception用于用户程序可以捕获的异常情况。Error定义了不期望被用户程序捕获的异常。45.throw和throws有什么区别?throw关键字用来在程序中明确的抛出异常,相反,throws语句用来表明方法不能处理的异常。每一个方法都必须要指定哪些异常不能处理,所以方法的调用者才能够确保处理可能发生的异常,多个异常是用逗号分隔的。46.异常处理完成以后,Exception对象会发生什么变化?Exception对象会在下一个垃圾回收过程中被回收掉。47.finally代码块和finalize()方法有什么区别?无论是否抛出异常,finally代码块都会执行,它主要是用来释放应用占用的资源。finalize()方法是Object类的一个protected方法,它是在对象被垃圾回收之前由Java虚拟机来调用的。48.什么是Applet?java applet是能够被包含在HTML页面中并且能被启用了java的客户端浏览器执行的程序。Applet主要用来创建动态交互的web应用程序。49.解释一下Applet的生命周期applet可以经历下面的状态:Init:每次被载入的时候都会被初始化。Start:开始执行applet。Stop:结束执行applet。Destroy:卸载applet之前,做最后的清理工作。50.当applet被载入的时候会发生什么?首先,创建applet控制类的实例,然后初始化applet,最后开始运行。51.Applet和普通的Java应用程序有什么区别?applet是运行在启用了java的浏览器中,Java应用程序是可以在浏览器之外运行的独立的Java程序。但是,它们都需要有Java虚拟机。进一步来说,Java应用程序需要一个有特定方法签名的main函数来开始执行。Java applet不需要这样的函数来开始执行。最后,Java applet一般会使用很严格的安全策略,Java应用一般使用比较宽松的安全策略。52.Java applet有哪些限制条件?主要是由于安全的原因,给applet施加了以下的限制:applet不能够载入类库或者定义本地方法。applet不能在宿主机上读写文件。applet不能读取特定的系统属性。applet不能发起网络连接,除非是跟宿主机。applet不能够开启宿主机上其他任何的程序。53.什么是不受信任的applet?不受信任的applet是不能访问或是执行本地系统文件的Java applet,默认情况下,所有下载的applet都是不受信任的。54.从网络上加载的applet和从本地文件系统加载的applet有什么区别?当applet是从网络上加载的时候,applet是由applet类加载器载入的,它受applet安全管理器的限制。当applet是从客户端的本地磁盘载入的时候,applet是由文件系统加载器载入的。从文件系统载入的applet允许在客户端读文件,写文件,加载类库,并且也允许执行其他程序,但是,却通不过字节码校验。55.applet类加载器是什么?它会做哪些工作?当applet是从网络上加载的时候,它是由applet类加载器载入的。类加载器有自己的java名称空间等级结构。类加载器会保证来自文件系统的类有唯一的名称空间,来自网络资源的类有唯一的名称空间。当浏览器通过网络载入applet的时候,applet的类被放置于和applet的源相关联的私有的名称空间中。然后,那些被类加载器载入进来的类都是通过了验证器验证的。验证器会检查类文件格式是否遵守Java语言规范,确保不会出现堆栈溢出(stack overflow)或者下溢(underflow),传递给字节码指令的参数是正确的。56.applet安全管理器是什么?它会做哪些工作?applet安全管理器是给applet施加限制条件的一种机制。浏览器可以只有一个安全管理器。安全管理器在启动的时候被创建,之后不能被替换覆盖或者是扩展。57.什么是JDBC?JDBC是允许用户在不同数据库之间做选择的一个抽象层。JDBC允许开发者用JAVA写数据库应用程序,而不需要关心底层特定数据库的细节。58.解释下驱动(Driver)在JDBC中的角色。JDBC驱动提供了特定厂商对JDBC API接口类的实现,驱动必须要提供java.sql包下面这些类的实现:Connection, Statement, PreparedStatement,CallableStatement, ResultSet和Driver。59.Class.forName()方法有什么作用?初始化参数指定的类,并且返回此类对应的Class 对象60.PreparedStatement比Statement有什么优势?PreparedStatements是预编译的,因此,性能会更好。同时,不同的查询参数值,PreparedStatement可以重用。61.什么时候使用CallableStatement?用来准备CallableStatement的方法是什么?CallableStatement用来执行存储过程。存储过程是由数据库存储和提供的。存储过程可以接受输入参数,也可以有返回结果。非常鼓励使用存储过程,因为它提供了安全性和模块化。准备一个CallableStatement的方法是:CallableStament.prepareCall();62.数据库连接池是什么意思?像打开关闭数据库连接这种和数据库的交互可能是很费时的,尤其是当客户端数量增加的时候,会消耗大量的资源,成本是非常高的。可以在应用服务器启动的时候建立很多个数据库连接并维护在一个池中。连接请求由池中的连接提供。在连接使用完毕以后,把连接归还到池中,以用于满足将来更多的请求。63.什么是RMI?Java远程方法调用(Java RMI)是Java API对远程过程调用(RPC)提供的面向对象的等价形式,支持直接传输序列化的Java对象和分布式垃圾回收。远程方法调用可以看做是激活远程正在运行的对象上的方法的步骤。RMI对调用者是位置透明的,因为调用者感觉方法是执行在本地运行的对象上的。64.RMI体系结构的基本原则是什么?RMI体系结构是基于一个非常重要的行为定义和行为实现相分离的原则。RMI允许定义行为的代码和实现行为的代码相分离,并且运行在不同的JVM上。65.RMI体系结构分哪几层?RMI体系结构分以下几层:存根和骨架层(Stub and Skeleton layer):这一层对程序员是透明的,它主要负责拦截客户端发出的方法调用请求,然后把请求重定向给远程的RMI服务。远程引用层(Remote Reference Layer):RMI体系结构的第二层用来解析客户端对服务端远程对象的引用。这一层解析并管理客户端对服务端远程对象的引用。连接是点到点的。传输层(Transport layer):这一层负责连接参与服务的两个JVM。这一层是建立在网络上机器间的TCP/IP连接之上的。它提供了基本的连接服务,还有一些防火墙穿透策略。66.RMI中的远程接口(Remote Interface)扮演了什么样的角色?远程接口用来标识哪些方法是可以被非本地虚拟机调用的接口。远程对象必须要直接或者是间接实现远程接口。实现了远程接口的类应该声明被实现的远程接口,给每一个远程对象定义构造函数,给所有远程接口的方法提供实现。67.java.rmi.Naming类扮演了什么样的角色?java.rmi.Naming类用来存储和获取在远程对象注册表里面的远程对象的引用。Naming类的每一个方法接收一个URL格式的String对象作为它的参数。68.RMI的绑定(Binding)是什么意思?绑定是为了查询找远程对象而给远程对象关联或者是注册以后会用到的名称的过程。远程对象可以使用Naming类的bind()或者rebind()方法跟名称相关联。69.Naming类的bind()和rebind()方法有什么区别?bind()方法负责把指定名称绑定给远程对象,rebind()方法负责把指定名称重新绑定到一个新的远程对象。如果那个名称已经绑定过了,先前的绑定会被替换掉。70.让RMI程序能正确运行有哪些步骤?为了让RMI程序能正确运行必须要包含以下几个步骤:编译所有的源文件。使用rmic生成stub。启动rmiregistry。启动RMI服务器。运行客户端程序。71.RMI的stub扮演了什么样的角色?远程对象的stub扮演了远程对象的代表或者代理的角色。调用者在本地stub上调用方法,它负责在远程对象上执行方法。当stub的方法被调用的时候,会经历以下几个步骤:初始化到包含了远程对象的JVM的连接。序列化参数到远程的JVM。等待方法调用和执行的结果。反序列化返回的值或者是方法没有执行成功情况下的异常。把值返回给调用者。72.什么是分布式垃圾回收(DGC)?它是如何工作的?DGC叫做分布式垃圾回收。RMI使用DGC来做自动垃圾回收。因为RMI包含了跨虚拟机的远程对象的引用,垃圾回收是很困难的。DGC使用引用计数算法来给远程对象提供自动内存管理。73.RMI中使用RMI安全管理器(RMISecurityManager)的目的是什么?RMISecurityManager使用下载好的代码提供可被RMI应用程序使用的安全管理器。如果没有设置安全管理器,RMI的类加载器就不会从远程下载任何的类。74.解释下Marshalling和demarshalling。当应用程序希望把内存对象跨网络传递到另一台主机或者是持久化到存储的时候,就必须要把对象在内存里面的表示转化成合适的格式。这个过程就叫做Marshalling,反之就是demarshalling。75.解释下Serialization和Deserialization。Java提供了一种叫做对象序列化的机制,他把对象表示成一连串的字节,里面包含了对象的数据,对象的类型信息,对象内部的数据的类型信息等等。因此,序列化可以看成是为了把对象存储在磁盘上或者是从磁盘上读出来并重建对象而把对象扁平化的一种方式。反序列化是把对象从扁平状态转化成活动对象的相反的步骤。76.什么是Servlet?Servlet是用来处理客户端请求并产生动态网页内容的Java类。Servlet主要是用来处理或者是存储HTML表单提交的数据,产生动态内容,在无状态的HTTP协议下管理状态信息。77.说一下Servlet的体系结构。所有的Servlet都必须要实现的核心的接口是javax.servlet.Servlet。每一个Servlet都必须要直接或者是间接实现这个接口,或者是继承javax.servlet.GenericServlet或者javax.servlet.http.HTTPServlet。最后,Servlet使用多线程可以并行的为多个请求服务。78.Applet和Servlet有什么区别?Applet是运行在客户端主机的浏览器上的客户端Java程序。而Servlet是运行在web服务器上的服务端的组件。applet可以使用用户界面类,而Servlet没有用户界面,相反,Servlet是等待客户端的HTTP请求,然后为请求产生响应。79.GenericServlet和HttpServlet有什么区别?GenericServlet是一个通用的协议无关的Servlet,它实现了Servlet和ServletConfig接口。继承自GenericServlet的Servlet应该要覆盖service()方法。最后,为了开发一个能用在网页上服务于使用HTTP协议请求的Servlet,你的Servlet必须要继承自HttpServlet。80.解释下Servlet的生命周期。对每一个客户端的请求,Servlet引擎载入Servlet,调用它的init()方法,完成Servlet的初始化。然后,Servlet对象通过为每一个请求单独调用service()方法来处理所有随后来自客户端的请求,最后,调用Servlet的destroy()方法把Servlet销毁。81.doGet()方法和doPost()方法有什么区别?doGet:GET方法会把名值对追加在请求的URL后面。因为URL对字符数目有限制,进而限制了用在客户端请求的参数值的数目。并且请求中的参数值是可见的,因此,敏感信息不能用这种方式传递。doPOST:POST方法通过把请求参数值放在请求体中来克服GET方法的限制,因此,可以发送的参数的数目是没有限制的。最后,通过POST请求传递的敏感信息对外部客户端是不可见的。82.什么是Web应用程序?Web应用程序是对Web或者是应用服务器的动态扩展。有两种类型的Web应用:面向表现的和面向服务的。面向表现的Web应用程序会产生包含了很多种标记语言和动态内容的交互的web页面作为对请求的响应。而面向服务的Web应用实现了Web服务的端点(endpoint)。一般来说,一个Web应用可以看成是一组安装在服务器URL名称空间的特定子集下面的Servlet的集合。83.什么是服务端包含(Server Side Include)?服务端包含(SSI)是一种简单的解释型服务端脚本语言,大多数时候仅用在Web上,用servlet标签嵌入进来。SSI最常用的场景把一个或多个文件包含到Web服务器的一个Web页面中。当浏览器访问Web页面的时候,Web服务器会用对应的servlet产生的文本来替换Web页面中的servlet标签。84.什么是Servlet链(Servlet Chaining)?Servlet链是把一个Servlet的输出发送给另一个Servlet的方法。第二个Servlet的输出可以发送给第三个Servlet,依次类推。链条上最后一个Servlet负责把响应发送给客户端。85**.如何知道是哪一个客户端的机器正在请求你的Servlet?**ServletRequest类可以找出客户端机器的IP地址或者是主机名。getRemoteAddr()方法获取客户端主机的IP地址,getRemoteHost()可以获取主机名86.什么是cookie?session和cookie有什么区别?cookie是Web服务器发送给浏览器的一块信息。浏览器会在本地文件中给每一个Web服务器存储cookie。以后浏览器在给特定的Web服务器发请求的时候,同时会发送所有为该服务器存储的cookie。下面列出了session和cookie的区别:无论客户端浏览器做怎么样的设置,session都应该能正常工作。客户端可以选择禁用cookie,但是,session仍然是能够工作的,因为客户端无法禁用服务端的session。在存储的数据量方面session和cookies也是不一样的。session能够存储任意的Java对象,cookie只能存储String类型的对象。87.什么是HTTP隧道?HTTP隧道是一种利用HTTP或者是HTTPS把多种网络协议封装起来进行通信的技术。因此,HTTP协议扮演了一个打通用于通信的网络协议的管道的包装器的角色。把其他协议的请求掩盖成HTTP的请求就是HTTP隧道。88.sendRedirect()和forward()方法有什么区别?sendRedirect()方法会创建一个新的请求,而forward()方法只是把请求转发到一个新的目标上。重定向(redirect)以后,之前请求作用域范围以内的对象就失效了,因为会产生一个新的请求,而转发(forwarding)以后,之前请求作用域范围以内的对象还是能访问的。一般认为sendRedirect()比forward()要慢。89.JSP请求是如何被处理的?浏览器首先要请求一个以.jsp扩展名结尾的页面,发起JSP请求,然后,Web服务器读取这个请求,使用JSP编译器把JSP页面转化成一个Servlet类。需要注意的是,只有当第一次请求页面或者是JSP文件发生改变的时候JSP文件才会被编译,然后服务器调用servlet类,处理浏览器的请求。一旦请求执行结束,servlet会把响应发送给客户端。这里看下如何在JSP中获取请求参数。90.什么是JSP指令(Directive)?JSP中有哪些不同类型的指令?Directive是当JSP页面被编译成Servlet的时候,JSP引擎要处理的指令。Directive用来设置页面级别的指令,从外部文件插入数据,指定自定义的标签库。Directive是定义在 <%@ 和 %>之间的。下面列出了不同类型的Directive:包含指令(Include directive):用来包含文件和合并文件内容到当前的页面。页面指令(Page directive):用来定义JSP页面中特定的属性,比如错误页面和缓冲区。Taglib指令: 用来声明页面中使用的自定义的标签库。91.什么是JSP动作(JSP action)?JSP动作以XML语法的结构来控制Servlet引擎的行为。当JSP页面被请求的时候,JSP动作会被执行。它们可以被动态的插入到文件中,重用JavaBean组件,转发用户到其他的页面,或者是给Java插件产生HTML代码。下面列出了可用的动作:jsp:include-当JSP页面被请求的时候包含一个文件。jsp:useBean-找出或者是初始化Javabean。jsp:setProperty-设置JavaBean的属性。jsp:getProperty-获取JavaBean的属性。jsp:forward-把请求转发到新的页面。jsp:plugin-产生特定浏览器的代码。92.什么是Scriptlets?JSP技术中,scriptlet是嵌入在JSP页面中的一段Java代码。scriptlet是位于标签内部的所有的东西,在标签与标签之间,用户可以添加任意有效的scriplet。93**对于JSP,隐含对象是什么意思?有哪些隐含对象?**JSP隐含对象是页面中的一些Java对象,JSP容器让这些Java对象可以为开发者所使用。开发者不用明确的声明就可以直接使用他们。JSP隐含对象也叫做预定义变量。下面列出了JSP页面中的隐含对象:applicationpagerequestresponsesessionexceptionoutconfigpageContext————————————————
  • [技术干货] java开发必备三大修饰符之final
    三、final 最终的 修饰变量 局部变量:final修饰的局部变量只能赋值一次 值一旦赋值不可以改变常量的定义:    public static final double PI = 3.14159265457;案例:public class Demo{   public static void main(String[] args) {       int a = 20;//局部变量        final int b = 10;        a++;       b++;       System.out.println(a);       System.out.println(b);            }   }public class Demo{   public static void main(String[] args) {       final int a ;//声明       a = 10;        a = 20;//报错        System.out.println(a);            }   }实例变量    特点:   1.final修饰的实例变量没有默认值   2.final修饰的实例变量只能赋值一次    3.final修饰的实例变量可以在构造方法中初始化 但是要保证每个构造都必须能够为这个变量初始化案例:public class Demo{    public static void main(String[] args) {       Animal a = new Animal(250);       //System.out.println(a.a);//0        System.out.println(a.b);                              }  }class Animal{    /*int a = 10;//实例变量   final int b = 20;*/    int a;   final int b = 20;    public  Animal(int b) {       this.b = b;   }  }public class Demo{   public static void main(String[] args) {       Animal a = new Animal(250);       //System.out.println(a.a);//0        System.out.println(a.b);                              }   }class Animal{   /*int a = 10;//实例变量    final int b = 20;*/    int a;    final int b ;   public  Animal(int b){        this.b = b;    }    public  Animal() {       b = 30;    }  }类变量特点:   1.final修饰的类变量没有默认值    2.final修饰的类变量可以通过静态代码块进行初始化案例:public class Demo{    public static void main(String[] args) {        System.out.println(Animal.a);        System.out.println(Animal.b);                               }   }class Animal{    static int a ;    final static int b ;    static{        b = 250;    }          }  修饰方法成员方法:特点:    1.final修饰的成员方法修饰类 语法:final class Animal{}特点:final修饰的类没有子类 俗称断子绝孙类jdk的类库中有哪些final修饰的类?String  Math  System案例:public class Demo{    public static void main(String[] args) {             }   }class Dog extends System{     }  
  • [技术干货] java开发必备三大修饰符之static
    二、static 静态的  static修饰成员变量:类变量 静态变量 静态属性定义语法:访问修饰符  static   数据类型  变量名 = 变量值;   static   访问修饰符     数据类型  变量名 = 变量值;访问的方式(特点)   1.类变量可以用 类名.属性名 访问    2.可以通过创建对象 用引用去访问 (不推荐)案例:public class Demo{   public static void main(String[] args) {       Test t1 = new Test();            Test t2 = new Test();        t1.a++;       t1.b++;       System.out.println(t2.a);//10             System.out.println(t2.b);//21                     }      }class Test{  int a = 10;//实例变量   static int b = 20;//类变量  }案例2:public class Demo{    public static void main(String[] args) {       /*Test t1 = new Test();       Test t2 = new Test();       t1.a++;       t1.b++;       System.out.println(t2.a);       System.out.println(t2.b);*/       System.out.println(Test.b);//20      }      }class Test{   int a = 10;//实例变量   static int b = 20;//类变量  }  static修饰成员方法:静态方法语法:   访问修饰符  static  返回值类型  方法名(形参列表){       方法的实现;    }    static 访问修饰符    返回值类型  方法名(形参列表){       方法的实现;    }特点:   1.静态的方法中 不可以直接访问非静态的成员(成员变量 和  成员方法)    2.如果要访问非静态的成员  必须创建对象 通过引用取访问   3.静态方法可以通过 类名.方法名() 访问  也可以通过引用去访问(不建议)    4.静态的方法可以被继承   静态的方法不能被非静态的方法所覆盖 只能被静态方法覆盖  但是没有多态(引用是什么类型 调用的方法就是这个类型中的方法)   5.在静态方法中是不可以使用 this 和 super 关键字  因为 this 和 super都是和对象有关的  而静态的成员和对象无关 先于对象存在案例:关于静态方法 访问非静态的成员public class Demo{    public static void main(String[] args) {       /*Test t1 = new Test();       Test t2 = new Test();       t1.a++;       t1.b++;       System.out.println(t2.a);       System.out.println(t2.b);*/       //System.out.println(Test.b);//20                              }      }class Test{    int a = 10;//实例变量    static int b
  • [技术干货] java开发必备修饰符之抽象类
    一、abstract 抽象的抽象类:被abstract 修饰的类语法:abstract class  类名{}抽象方法 :被abstract 修饰的方法定义语法:   访问修饰符  abstract 返回值类型 方法名(参数列表);   abstract 访问修饰符   返回值类型 方法名(参数列表);特点:    1.当一个类中存在抽象方法 那么这个类也必须是抽象的    2.一个抽象类中可以有抽象方法也可以有非抽象方法    3.如果一个类继承了抽象类,这个类如果不想成为抽象类,那么这个类必须实现抽象类中的所有抽象方法    4.抽象类不能创建对象,但是可以声明引用,抽象类的对象是存在的,是由子类创建子类对象时调用父类构造方法创建的,是无法自己手动去new 抽象类的对象的抽象类的好处:强制使用多态案例:public class Demo{    public static void main(String[] args) {               }     }abstract class Animal{   //抽象方法    public abstract void eat();   public abstract  void sleep();    public void m1() {       System.out.println("m1");             }}class Dog extends Animal{   public  void eat(){        System.out.println("狗吃屎");            }    public  void sleep(){        System.out.println("狗睡");   }}案例:public class Demo{   public static void main(String[] args) {       Animal a = new Dog();     }     }abstract class Animal{   public  Animal() {       System.out.println("动物类的构造被调用 创建了 对象");            }              //抽象方法    abstract public  void eat();   public abstract  void sleep();    public void m1() {       System.out.println("m1");            }}class Dog extends Animal{    public  void eat(){        System.out.println("狗吃屎");            }   public  void sleep(){       System.out.println("狗睡");    }}  
  • [技术干货] Redis 支持的 Java 客户端
    支持的 Java 客户端有 Redisson、jedis、lettuce 等。
  • [技术干货] 访谈java之父为啥选择java的理由?
    微软的.NET和SUNone的争夺由来已久,并且有愈演愈烈之势,最近微软的Server2003活动刚落幕,在16日上午“Java之父”JamesGosling在北京出席第六届全国Java技术与应用大会,面对以COM+为核心Server2003凌厉攻势,让我们听听这位传奇人物是如何评价微软还有java的。  以下是James Gosling答记者和Java爱好者的提问:   “微软是一个很难合作的公司,在微软的字典里似乎没有合作二字!”                                JamesGosling   问:Sun近来与中国各移动厂商积极合作,发展无线增值服务,微软也刚刚开发了一组智能手机产品,Sun是如何应对的?   JamesGosling:微软是一个有意思的竞争伙伴,Sun的强大武器是Java技术本身,同时,Sun和合作伙伴达成紧密合作,极大的支持软件开发团队。9月26日,Sun与联通宣布结成联盟,这是联通看到了Java在手机市场的专有性和Java具有的开放性和标准性。Java欢迎竞争,因为只有这样才能最大限度的提高领域内的技术。 问:在近几年的发展过程中,很多编程语言都逐渐消失,而Java语言却越来越火热起来,请问您其中的秘诀在哪里?   JamesGosling:我认为,很多的编程语言在发展中并不是消失,而是转移到了其他领域中去,而Java的经久不衰,取决于Java的技术基础,如果你问编程师,为什么会选择Java,他会告诉你,Java提供了多种功能,提供了方便的平台,是个足以吸引人的工具。我认为,推动Java最主要的因素是网络,Java是以网络应用为基础的开发工具,这是它的强处。   问:在传统计算机领域中,Java并不是十分大的平台,如台式PC。而在其他领域,如移 动领域,Java发展迅速,Java的未来发展方向是什么?   JamesGosling:而在PC领域,我并不认为Java不够强大,在PC领域Java有很多应用,这是表面上看不到的,这主要是微软花了大力气避免用户看到,实际上Java应用很广泛,比如说人工智能游戏,在其他大的领域,Java更是应用广泛,例如在汽车,铁路机车上的即时控制系统,Java也广泛应用于军用方面。   问:在中国有很多人使用手机,使用移动方案,您认为在更新的设备上使用J2ME有什么看法?   JamesGosling:J2ME的规格在不断地进化,但是我们的规划过程主要是推动力是手机性能不断地增长。在两年前,当时手机比今天的性能要差得远。我拿的手机是一个诺基亚的手机,它有16兆的存储记忆,在几年之前我们会认为16兆只能在一个很强大的桌面机上实现,所以我们现在用手机可以做的工作现在变得越来越有趣,这个领域有非常光明、非常令人振奋的前景。   问:大家都敬称您为Java之父,您能不能跟大家分享一下你在Java事业中最深的感受是什么?   JamesGosling:当看到Java的客户通过Java完成了很多神奇的工作,像看到夏威夷火山上的观测台使用Java控制望远镜,看到荷兰健康医疗组织使用Java解决了保护隐私问题等等,那真是一种奇妙的感觉。  问:Sun一直称由Sun开发的web服务是最好的,能不能总结一下其特性,为什么这样认为。Sun在解决和微软的web组互操作上程度如何,Sun的web服务进展怎样?  JamesGosling:有太多的东西可以确定Java的优势,我认为其最大的优势在于,Java是集成了许多人努力而创建的强有力的工具,可以提供很多功能。Java满足网络服务标准,具有很强的安全性。Sun花了很大的力气在解决和微软的互操作性上,遵循国际网络业的标准与微软工具进行交流,开发了大量相关工具。微软是一个很难合作的公司,在微软的字典里似乎没有合作二字,Sun花了很大的力气去遵循微软标准,扩大互操作性。而Sun的web服务未来将向扩大web应用能力,扩大通用性和边缘应用上发展。  问:IBM与BEA在很多方面是Sun的合作伙伴,同时,在web服务上成绩也是名列前茅,Sun是如何看待与IBM和BEA等厂商的关系的,Sun认为自己的优势在哪里?  JamesGosling:Sun竞争依靠的是好的产品,Sun认为的是,市场越大就有更大的机会赚钱,Sun认为应该与像IBM,BEA等厂商合作共同开发市场,而不求垄断市场,打个比方来说,市场就像是一张饼,是一张小饼分走大的一块还是一张大饼分走小的一块。Sun的经营模式是致力于扩大市场,我认为这胜过微软的垄断市场策略。  问:你是否有过有关职业病的问题?现在好了吗?  JamesGosling:我有各种各样的职业病了,就是高度劳累的职业病。我的双手都有职业病的各种症状,但这种病实际上并不是很痛苦,只是你的神经会有一些麻木,可能不会有感觉。拿个刀子把手指砍下去可能你都不会知道,这种感觉非常可怕。如果你要坐在桌前,16个小时要是不停地在敲键盘,会有很大的损害,你一定要注意身体。16个小时工作绝不是好做法。
  • [技术干货] 如何分析java中的浮点数?
    浮点数分为单精度和双精度,Java中的单精度和双精度分别为float和double.你们知道float和double是怎么存储的吗?   float占4个字节,double占8个字节,为了方便起见,这里就只讨论float类型.   float其实和一个int型的大小是一样的,一共32位,第一位表示符号,2-9表示指数,后面23位表示小数部分.这里不多说,请参考:http://blog.csdn.net/treeroot/archive/2004/09/05/95071.aspx  这里只举一个例子,希望能抛砖引玉,就是研究一下浮点数0.1的存储形式,先运行这个程序.  public class Test{   public static void main(String[] args) {   int x = 0x3d800000;   int i = 1 << 22;   int j = 1 << 4;   float f = 0.1f;   int y = Float.floatToIntBits(f);   float rest = f - ( (float) 1) / j;  while (i > 0) {   j <<= 1;   float deta = ( (float) 1) / j;   if (rest >= deta) {   rest -= deta;   x |= i;   }   i >>= 1;   }   pr(x);   pr(y);   }  static void pr(int i) {   System.out.println(Integer.toBinaryString(i));   }  } 结果:   111101110011001100110011001101   111101110011001100110011001101  程序说明:   int x=0x3d80000;   因为浮点表示形式为1.f*2n-127我们要表示0.1,可以知道n-127=-4,到n=123   符号为正,可知前9是 001111011,暂时不考虑后面的23位小数,所以我们先假设x=0x3d800000;  int i = 1 << 22;   i初始为第右起第23位为1,就是x的第10位  int j = 1 << 4;   i初始为4,因为n-127为-4,这里是为了求它的倒数.  float f = 0.1f;   int y = Float.floatToIntBits(f);   y就是它的32位表示  float rest = f - ( (float) 1) / j;   这个rest表示除了1.f中的1剩下的,也就是0.f  while (i > 0) {   j <<= 1;   float deta = ( (float) 1) / j;   if (rest >= deta) {   rest -= deta;   x |= i;   }   i >>= 1;   }   这个循环来计算23位小数部分,如果rest不小于deta,表示这个位可以置为1.  其他的不多说了,输入结果是一样的,可以说0.1这个浮点数肯定是不精确的,但是0.5可以精确的表示,想想为什么吧
  • [互动交流] 明明是Hetu支持的字段类型,却报java.lang.UnsupportedOperationException错误
    有一个表,建表类型都是Hetu支持的类型,而且Hive查询都是正常的,Hetu查询却报java.lang.UnsupportedOperationException: io.prestosql.spi.type.VarcharType错误,如下:建表语句:Hive查询:Hetu查询:原因:出现此问题, 是因为Hetu内部默认是按照列的标号实现hdfs的文件切分成Page处理的,当hdfs的parquent或者orc的文件的列顺序和建表语句的列顺序不一致时,列会映射错位置,数据无法解释。解决方法:可以在将文件切分的方式改成列名映射,修改方法为:在hive.properties.customized.configs添加配置hive.parquet.use-column-names和hive.orc.use-column-names设置为true即可
  • [分享交流] 【JAVA编程创造营】强烈推荐
    推荐理由1. 基础不牢,地动山摇。这个创造营对JAVA基础抽丝剥茧讲的非常好,比人云亦云的教程绝对不一样~2.新鲜出炉,看老师午夜子时还在奋力录制教程,不强烈推荐对不起老师
  • [热门活动] 华为云博客“奔跑吧,JAVA!”有奖征文获奖名单正式出炉啦!让我们一同恭喜获奖者!
    “奔跑吧,JAVA!”有奖征文获奖名单正式出炉啦!让我们一同恭喜获奖者!大众评审团与专家评审团分别对最终入围的22篇优质文章进行了投票与打分,最终得出了一二三等奖,其他没有得奖的参与者也将获得大额码豆激励。昵称奖项奖品标题大众投票大众加权分评委加权分总分小傅哥一等奖JBL GO2音乐金砖给Java小白,整理一套能上手的简单编程算法题【含答案】!!!【奔跑吧!JAVA】601.694.46.09灰小猿一等奖JBL GO2音乐金砖【图文并茂】深度解析HashMap高频面试及底层实现结构!【奔跑吧!JAVA】411.164.85.96breakDraw一等奖JBL GO2音乐金砖java新手们必收藏的两本武林秘籍,java中的《降龙十八掌》和《九阴真经》分别是啥?【奔跑吧!JAVA】611.7245.72bigsai一等奖JBL GO2音乐金砖揭秘高效自学Java的方法和路线(从认识、方法、反馈3个角度出发)丨【奔跑吧!JAVA】591.6745.67breakDraw一等奖5000码豆java中的NIO和IO到底是什么区别?20个问题告诉你答案【奔跑吧!JAVA】361.024.65.62bigsai二等奖3000码豆「万字图文」史上最姨母级Java继承详解丨【奔跑吧!JAVA】200.5655.56breakDraw二等奖3000码豆“动态规划”这词太吓人,其实可以叫“状态缓存”【奔跑吧!JAVA】340.964.65.56ruochen二等奖华为便携充电宝20000mAH大话Java异常丨【奔跑吧!JAVA】250.714.65.31陈皮的JavaLib二等奖华为便携充电宝20000mAHSpring事件发布与监听机制丨【奔跑吧!JAVA】90.2555.25jackwangcumt二等奖华为便携充电宝20000mAHJava编程中容易忽略的细节总结丨【奔跑吧!JAVA】110.314.64.91ruochen三等奖2000码豆几行代码带你彻底搞懂Java内部类丨【奔跑吧!JAVA】250.714.24.91香菜聊游戏三等奖华为mini蓝牙音箱内存泄漏说的明明白白,解决办法清清楚楚【奔跑吧!JAVA】90.254.64.85陈皮的JavaLib三等奖2000码豆Spring Boot - 自定义 Banner 图案丨【奔跑吧!JAVA】70.204.64.80ruochen三等奖2000码豆JavaWeb 项目服务器部署详细教程(MySQL + JDK + Tomcat)丨【奔跑吧!JAVA】230.6544.65香菜聊游戏三等奖2000码豆从零复刻王者荣耀活动系统,策划都能看得懂的活动系统,源码奉送【奔跑吧!JAVA】60.174.44.57陈皮的JavaLib三等奖2000码豆【Spring系列】使用InitializingBean和DisposableBean来管理bean生命周期【奔跑吧!JAVA】50.144.44.54breakDraw三等奖2000码豆用1个例子加5个问题,一次性搞清java中的类加载问题【奔跑吧!JAVA】30.084.44.48陈皮的JavaLib三等奖2000码豆我是如何用 ThreadLocal 虐面试官的?丨【奔跑吧!JAVA】50.144.24.34jackwangcumt三等奖2000码豆JAVA编程不可不知的反射用法总结丨【奔跑吧!JAVA】40.114.24.31lwq1228三等奖华为mini蓝牙音箱[Java多线程四种常用创建方式【奔跑吧!JAVA】110.3144.31ruochen三等奖2000码豆Java 连接操作 MySQL 数据库(增删查改操作)【奔跑吧!JAVA】30.084.24.28香菜聊游戏三等奖2000码豆惊呆了,原来JavaIO如此简单【奔跑吧!JAVA】30.0844.08每位选手最终得分=获票数/总投票数 X 10 X 0.5+评委综合打分(10分满分)X 0.5昵称奖项奖品@Wu参与奖3000码豆aoho参与奖3000码豆franco52576参与奖3000码豆holo.yh参与奖3000码豆Jack20参与奖3000码豆liuzhen007参与奖3000码豆SHQ5785参与奖3000码豆sjwy参与奖3000码豆zekelove参与奖3000码豆爱学习的多宝参与奖3000码豆布小禅参与奖3000码豆代码哈士奇参与奖3000码豆多米诺的古牌参与奖3000码豆果冻906参与奖3000码豆考过IE励志当攻城狮参与奖3000码豆万猫学社参与奖3000码豆运气男孩参与奖3000码豆获奖信息收集请以上各位获奖者按如下操作:(参与奖无需回复信息)社区私信“技术火炬手”回复您的有效信息:姓名、手机号、电子邮箱、收货地址注:有效信息反馈期为1周(20号截止),超过时限未收到您的信息,则视为自动弃奖,过期不补请谅解!礼品预计在本月发出。有任何疑问请添加社区小助手微信(微信号:bbs_huaweicloud)让我们再次恭喜以上获奖者~今年五月,编程语言—JAVA迎来了自己的第26个生日。近年来,这位编程老牌大哥的地位却总是遭到许多人的质疑。随着互联网时代的发展,一些领域使用新的开发语言,在一定程度上抢占了Java的市场份额,但Java仍旧凭借自己的简单性、面向对象、分布式、健壮性、安全性、平**立与可移植性、多线程、动态性等特点,在互联网中得到了广泛的应用。华为云社区【Java】主题有奖征文开始啦!我们需要哪些主题的稿件?原则上,我们欢迎所有能帮助所有学习Java的人成长的文章!如基于自己的实际使用经验,分享对Java的技术分析、使用感受及在项目实战中的经验或踩坑指南等:你可以从以下几类主题和参考文章中,找到自己感兴趣的投稿方向:1、关于Java的基础知识,比如反射、泛型、线程、数组等在内的一些疑难点的学**结感悟。JAVA编程中常用到的线程和注意点总结https://bbs.huaweicloud.com/blogs/235226java知识点问题精选之反射https://bbs.huaweicloud.com/blogs/2521142、Java开发工具包JDK相关,比如近年来崛起的OpenJDK。Java JDK 10:下一代 Java 有哪些新特性?https://bbs.huaweicloud.com/blogs/1031583、JVM(Java虚拟机)相关,包括溢出、类加载机制、垃圾回收等。深入理解Java虚拟机(四): 虚拟机性能监控https://bbs.huaweicloud.com/blogs/1281464、Java开发框架相关:Spring 、Spring MVC、Spring security、Spring Boot、Mybatis等等。基于CSE的微服务架构实践-Spring Boot技术栈选型https://bbs.huaweicloud.com/blogs/1159615、JAVA需要掌握的基础工具和基本技能,如:GIT、单元测试Java单元测试之JUnit 5快速上手https://bbs.huaweicloud.com/blogs/1191786、JAVA后端开发:Servlet、Java操作数据库、Java的分布式开发Java数据库访问方案探究https://bbs.huaweicloud.com/blogs/1982817、结合您的JAVA开发生涯,说说在书籍、学习方法、开发应用及面试中独家小秘籍;或者讲讲您的个人见解感悟、谈谈对于JAVA的“诗和远方”。【原创】Java学习路线以及方法推荐https://bbs.huaweicloud.com/blogs/127049你将获得什么?我们会把收到的优质内容汇编成册,并注明原作者,积累行业口碑,开放给圈内开发者下载查阅,提供实践参考。对于贡献优质内容的作者,我们还将送出JBL音箱,华为硬核充电宝等各项大礼!同时,在华为云站内外10+个技术社区醒目位置进行推荐,给与百万级流量资源。希望最终的这份《JAVA实战手册》精选集,有你的署名。优质作者更可获得长期约稿和更多内容合作机会。评奖规则说明奖品评选依据 :文章投票数50%+专家评审打分50%投票流程 :6月30日截稿后评审会选出15-25篇最优秀的文章到论坛进行投票。投票链接 :7月5日开启投票,更新投票链接。专家评分依据 :文章篇幅、技术含金量、排版美观度、阅读量、点赞、收藏等指标综合评分其他说明 :1、一二三等奖不能叠加。2、以上所有奖项可以与云社区“云驻计划”激励叠加。 点击了解云驻计划在哪里投稿?2、文章需要发表在社区博客; 是时候展现真正的技术了, 点击前往发布标题以 【奔跑吧!JAVA】结尾,例如:JAVA编程中常用到的线程和注意点总结丨【奔跑吧!JAVA】。文章末尾需加上活动名称及链接地址:【奔跑吧!JAVA】有奖征文火热进行中:https://bbs.huaweicloud.com/blogs/265241有哪些需要注意的1、文章内容需体现技术看点,图文并茂,建议字数在500字以上;2、文章要求为投稿人原创,凡转载或抄袭一经发现将取消参赛资格;3、文章须在华为云社区为首发,如华为云平台已有文章内容则视为稿件无效;4、稿件投稿后,华为云拥有该稿件的使用权、修改权等。快来华为云社区博客,一起和JAVA奔跑吧! 点击立即发布如果有任何问题,可添加华为云社区小助手微信号:bbs_huaweicloud,进行沟通咨询。添加微信时请备注:奔跑吧Java+报名活动时使用的华为云昵称!扫码添加小助手:
  • 每日10道面试题打卡——Java基础知识篇
    1、请你说一下什么是面向对象?Java是面向对象的编程语言,不同于C语言是面向过程的。对于面向对象和面向过程的区别,举一个简单的例子说明一下(我们以洗衣机洗衣服为例):面向过程:面向过程的编程方式,程序会将要完成的某一个任务拆解成一系列的小步骤 (函数),如:① 打开洗衣机:method01()② 放入要洗的衣服:method02()③ 放入洗衣服:method03()④ 清洗:method04()⑤ 烘干:method05()面向对象:面向对象的编程方式,程序会将要完成的洗衣机洗衣服的任务拆分成如下两个对象:人(Person):Person在洗衣机洗衣服这个程序任务中有三个作用,分别是打开洗衣机、放入要洗的衣服、放入洗衣粉。洗衣机(Machine):Machine在洗衣机洗衣服这个程序任务中有两个作用,分别是清洗、烘干。从上面这个例子能看出,面向过程的编程方式比较直接且高效,而面向对象的编程方式更易复用、扩展和维护!2、请你简述一下面向对象的三个基本特征?继承:承是Java中面向对象最显著的一个特征,继承是从已有的类中派生出新的类,新的类可以吸收已有的属性、行为,并扩展新的能力。Java中不支持多继承,但是接口可以支持多实现。封装:将同一类事物的特征和功能包装在一起,只对外暴露需要调用的接口。封装也称为信息的隐藏,在Java中接口是体现封装最常用的方法,在接口中我们没有任何功能的实现(具体实现都交给实现类),只是定义了一系列抽象的方法声明用于外部调用。多态:封装和继承都是为多态来服务的,多态是指同一个行为具有多个不同的表现形式。在Java中方法的重载和重写是实现多态的2种方式。重载发生在一个类中,同名的方法如果有不同的参数列表(参数类型不同、参数个数不同或者二者都不同)则视为重载。方法重载体现了编译时的多态性。重写发生在子类与父类之间,重写要求子类被重写方法与父类被重写方法有相同的返回类型,重载对返回类型没有特殊的要求。方法重写体现了运行时的多态性。多态的三要素:继承 、重写、父类指向子类引用!3、为什么说 Java 是一种半解释半编译的程序设计语言呢?什么是编译形语言,什么又是解释形语言?编译型语言:把做好的源程序全部编译成二进制代码的可运行程序。然后,就可以直接运行这个程序。执行速度快,效率高,依靠编译器,跨平台性稍差。解释型语言:把已经做好的源程序,翻译一句,执行一句,直到结束。执行速度慢,效率低,依靠编译器,但是跨平台性稍好。那么为什么说Java 是编译型语言呢?第一个观点认为 Java 是编译型语言,因为Java程序想要运行,那么第一步就是要使用Javac进行编译(将Java源文件编译成.class二进制文件)。没有经过编译的.java文件,是没办法运行的!那么为什么又说Java 是解释型语言呢?那么第二个观点则是认为Java是解释型语言,Java经过编译,Javac 将.java源文件编译成.class二进制文件之后,仍然需要借助 JVM 的解释执行。综合上面两个观点来看,Java似乎既有编译型语言的特点,又有解释型语言的特点,也没有看到哪本权威的书籍上认定Java就是哪一种类型的语言。4、请你说一下Java中的8大基本类型是那些?如图所示:8种基本数据类型和取值范围:基本类型    大小(位/bit)    字节数(byte)    最小值    最大值    默认值    包装器类型boolean    -    -    false    true    false    Booleanchar    16 bits    2 bytes    Unicode 0    Unicode 2^16-1    空    Characterbyte    8 bits    1 byte    -2^7    2^7-1    0    Byteshort    16 bits    2 bytes    -2~15    2^15-1    0    Shortint    32 bits    4 bytes    -2^31    2^31-1    0    Integerlong    64 bits    8 bytes    -2^63    2^63-1    0    Longfloat    32 bits    4 bytes            0.0    Floaddouble    64 bits    8 bytes            0.0    Double注意:对于boolean值,在Java规范中并没有给出其储存大小,在《Java虚拟机规范》中给出了4个字节,和boolean数组1个字节的定义,具体还要看虚拟机实现是否按照规范来,所以1个字节、4个字节都是有可能的。除了void之外,其他8种基本数据类型被称为八大基本数据类型。图中从左向右的转换都是隐式转换,无需再代码中进行强制转换。从右向左均要进行强制类型转换,才能通过编译。强制转换会丢失精度。5、请你讲讲抽象类和接口有什么区别?(一) 继承方面:抽象类只能单继承;而接口可以多实现;(二) 成员属性方面:抽象类中可以有普通属性,也可以有常量;接口中的成员变量全部默认是常量,使用public static final修饰,这个可以省略不写;(三) 代码块方面:抽象类可以含初始化块;接口不能含初始化块;(四) 构造函数方面:抽象类可以有构函数,但是这里的构造函数不是用来创建对象的,而且用来被实现类调用进行初始化操作的;接口不能有构造函数;(五) 方法方面:接口在JDK1.8之后可以定义抽象方法(无方法体)、default 修饰的默认方法(有方法体)、static修饰的静态方法(有方法体),JDK1.8以前是只能有抽象方法。public interface Test {     static void test() {     }         default void test2(){     }         void test3();// 默认是abstract修饰 }抽象类中除了静态方法和抽象方法外还可以有普通方法。二者相同之处接口与抽象类都不能被实例化,需要被其他进行实现或继承。接口与抽象类里面都能包含抽象方法,实现接口或继承抽象类的子类都必须实现这些抽象方法。6、请判断当一个对象被当作参数传递给一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递?是值传递。java 编程语言只有值传递参数。当一个对象实例作为一个参数被传递到方法中时,参数的值就是对该对象的引用。对象的内容可以在被调用的方法中改变,但对象的引用是永远不会改变的。java中只有值传递,基本类型传递的是值的副本,引用类型传递的是引用的副本7、请你说一下JVM/JRE/JDK的区别?直接看一张图就可以理解他们的区别了:JVM = Java虚拟机JRE = JVM + 基础类库JDK = JVM + 基础类库 + 编译工具8、请你说一下方法重载和方法重写的区别?重载:方法重载发生在同一个类中,重载的方法之间方法名必须相同,参数列表不同(参数的类型、参数的个数),方法的返回值和访问修饰符可以不同,发生在编译时期(方法重载实现了编译时多态)。重写:方法重写发生在子父类中,子类重写父类的方法,方法名称必须相同,参数列表也必须相同,方法的返回值小于等于父类方法的返回值,访问修饰符方位大于等于父类方法(如果父类方法修饰符为private,则子类就无法重写了)。9、请你说一下List接口和Set接口的区别?List:有序、可重复集合。按照对象插入的顺寻保存数据,允许多个Null元素对象,可以使用iterator迭代器遍历,也可以使用get(int index)方法获取指定下标元素。Set:无序、不可重复集合只允许有一个Null元素对象,取元素时,只能使用iterator迭代器逐一遍历。10、为什么重写了equals()方法还需要重写hashCode()方法?equals()只是判断对象属性是否相同,hashCode()要判断二者地址是否相同。java中如果要判断两个对象是否相等,需要同时满足地址 + 属性都相同!如果两个对象相同(即:用 equals() 比较返回true),那么它们的 hashCode 值一定要相同;如果两个对象的 hashCode 相同,它们并不一定相同;举例子:只重写 equals() 方法,不重写 hashcode() 方法:public class Student {    private String name;    private int age;     public Student(String name, int age) {        super();        this.name = name;        this.age = age;    }    @Override    public boolean equals(Object obj) {        if (this == obj)            return true;        if (obj == null)            return false;        if (getClass() != obj.getClass())            return false;        Student other = (Student) obj;        if (age != other.age)            return false;        if (name == null) {            if (other.name != null)                return false;        } else if (!name.equals(other.name))            return false;        return true;    }    // 省略 get,set方法...}执行下面的程序看看效果:public class hashTest {    @Test    public void test() {        Student stu1 = new Student("Jimmy",24);        Student stu2 = new Student("Jimmy",24);                System.out.println("两位同学是同一个人吗?"+stu1.equals(stu2));        System.out.println("stu1.hashCode() = "+stu1.hashCode());        System.out.println("stu1.hashCode() = "+stu2.hashCode());    }}如果重写了 equals() 而未重写 hashcode() 方法,可能就会出现两个没有关系的对象 equals 相同(因为equals都是根据对象的特征进行重写的),但 hashcode 不相同的情况。因为此时 Student 类的 hashcode() 方法就是 Object 默认的 hashcode()方 法,由于默认的 hashcode()方法是根据对象的内存地址经哈希算法得来的,所以 stu1 != stu2,故两者的 hashcode 值不一定相等。根据 hashcode 的规则,两个对象相等其 hash 值一定要相等,矛盾就这样产生了。上面我们已经解释了为什么要使用 hashcode 算法,所以即使字面量相等,但是产生两个不同的 hashCode 值显然不是我们想要的结果。如果我们在重写 equals() 时,也重写了 hashCode() 方法:public class Student {    private String name;    private int age;        public Student(String name, int age) {        super();        this.name = name;        this.age = age;    }    @Override    public int hashCode() {        final int prime = 31;        int result = 1;        result = prime * result + age;        result = prime * result + ((name == null) ? 0 : name.hashCode());        return result;    }    @Override    public boolean equals(Object obj) {        if (this == obj)            return true;        if (obj == null)            return false;        if (getClass() != obj.getClass())            return false;        Student other = (Student) obj;        if (age != other.age)            return false;        if (name == null) {            if (other.name != null)                return false;        } else if (!name.equals(other.name))            return false;        return true;    }    // 省略 get,set方法...}再来看执行结果:两位同学是同一个人吗?truestu1.hashCode() = 71578563stu1.hashCode() = 71578563从 Student 类重写后的 hashcode() 方法中可以看出,重写后返回的新的 hash 值与 Student 的两个属性是有关,这样就确保了对象和对象地址之间的关联性。
  • [问题求助] 【abc产品】【编码转换功能】ABC的script脚本如何将字符串转换成GBK编码? 租户:ncec1234
    【功能模块】script脚本如何将字符串转换成GBK编码?【操作步骤&问题现象】1、 java输入字符串 URLEncoder.encode("您的图纸已通过审核6666主场通知66", "GBK")      java的执行结果:%C4%FA%B5%C4%CD%BC%D6%BD%D2%D1%CD%A8%B9%FD%C9%F3%BA%CB6666%D6%F7%B3%A1%CD%A8%D6%AA662、abc的script输入字符串 let str = "您的图纸已通过审核6666主场通知66";let abcResult = iconv.encode(str, "GBK");abc输出结果:[ 196, 250, 181, 196, 205, 188, 214, 189, 210, 209, 205, 168, 185, 253, 201, 243, 186, 203, 54, 54, 54, 54, 214, 247, 179, 161, 205, 168, 214, 170, 54, 54 ] iconv.encode()如何输出java这种编码?在线编码工具的输出也和java输出一致3.script脚本其他方法测试结果:let abcResult2 = signer.urlEncode(str);结果:%E6%82%A8%E7%9A%84%E5%9B%BE%E7%BA%B8%E5%B7%B2%E9%80%9A%E8%BF%87%E5%AE%A1%E6%A0%B86666%E4%B8%BB%E5%9C%BA%E9%80%9A%E7%9F%A566let abcResult3 = escape(str);结果:%u60A8%u7684%u56FE%u7EB8%u5DF2%u901A%u8FC7%u5BA1%u68386666%u4E3B%u573A%u901A%u77E566let abcResult4 = encodeURI(str);结果:%E6%82%A8%E7%9A%84%E5%9B%BE%E7%BA%B8%E5%B7%B2%E9%80%9A%E8%BF%87%E5%AE%A1%E6%A0%B86666%E4%B8%BB%E5%9C%BA%E9%80%9A%E7%9F%A566let abcResult5 = encodeURIComponent(str);结果:%E6%82%A8%E7%9A%84%E5%9B%BE%E7%BA%B8%E5%B7%B2%E9%80%9A%E8%BF%87%E5%AE%A1%E6%A0%B86666%E4%B8%BB%E5%9C%BA%E9%80%9A%E7%9F%A566【截图信息】【日志信息】(可选,上传日志内容或者附件)
总条数:2294 到第 页
上滑加载中