1. javac 命令的作用;
1 javac 编译器解析 Java 源代码,并生成字节码文件的过程
2. java为什么可以跨平台;
1 ava有虚拟机(JVM),JAVA程序不是直接在电脑上运行的,是在虚拟机上进行的,每个系统平台都是有自己的虚拟机(JVM),所以JAVA语言能跨平台。 2 1, java代码不是直接运行在CPU上,而是运行在java虚机(简称JVM)上的。 3 2,java是先把java文件编译成二进制字节码的class文件,jvm就解释执行class文件。 4 3,就是因为java是运行在jvm上的,所以它的代码就能不经修改,就能在不同平台的jvm上运行(在UNIX用UNIX的jvm,在linux上用linux的jvm,在windows上用windows的jvm)
3. 变量(标示符)的命名规则;
1 标示符是用来给类,对象,方法,变量,接口和自定义数据类型命名的。凡是可以自己取名字的地方都叫做标示符,都要遵循标示符的规则。 2 3 标示符的规则:1.由数字,字母和下划线(_),美元符号($)组成。 4 5 2.区分大小写,首字母不能数字,长度无限制。 6 7 3.不能与java关键字重名
4. 基本数据类型有哪些(扩展:各类型的范围);
1 byte:Java中最小的数据类型,在内存中占8位(bit),即1个字节,取值范围-128~127,默认值0 2 3 short:短整型,在内存中占16位,即2个字节,取值范围-32768~32717,默认值0 4 5 int:整型,用于存储整数,在内在中占32位,即4个字节,取值范围-2147483648~2147483647,默认值0 6 7 long:长整型,在内存中占64位,即8个字节-2^63~2^63-1,默认值0L 8 9 float:浮点型,在内存中占32位,即4个字节,用于存储带小数点的数字(与double的区别在于float类型有效小数点只有6~7位),默认值0 10 11 double:双精度浮点型,用于存储带有小数点的数字,在内存中占64位,即8个字节,默认值0 12 13 char:字符型,用于存储单个字符,占16位,即2个字节,取值范围0~65535,默认值为空 14 15 boolean:布尔类型,占1个字节,用于判断真或假(仅有两个值,即true、false),默认值false
5. 编写冒泡排序法;
顾名思义,冒泡排序法就是让数组元素像水中的气泡一样逐渐上浮,进而达到排序的目的。 5 bubbleSort(A, N) 6 flag = 1 7 while flag 8 flag = 0 9 for j 从 N-1 到 1 10 if A[j] < A[j-1] 11 A[j]与A[j-1]交换 12 flag = 1 13 ________________________________________ 14 int bubbleSort(A, N) 15 { 16 bool flag = 1; 17 for(int i=0;flag;i++) 18 { 19 flag = 0; 20 for(int j = N-1;j >= i + 1;j--) 21 { 22 if(A[j]<A[j-1]) 23 { 24 swap(A[j],A[j-1]); 25 flag = 1; 26 } 27 } 28 } 29 }
6. switch语句switch后面括号中的可以填写的数据类型有哪些;
1 一般格式: 2 switch (表达式) 3 { 4 case 常量标号1:语句序列1; 5 break; 6 case 常量标号2:语句序列2; 7 break; 8 … 9 case 常量标号n:语句序列n; 10 break; 11 default: 语句S; 12 } 13 其中: 14 ①表达式:可以控制程序的执行过程,表达式的结果必须是整数、字符或枚举量值。 15 ②case后面的常量标号,其类型应与表达式的数据类型相同。表示根据表达式计算的结果,可能在case的标号中找到,标号不允许重复,具有唯一性,所以,只能选中一个case标号。尽管标号的顺序可以任意的,但从可读性角度而言,标号应按顺序排列。 16 ③语句序列是switch语句的执行部分。针对不同的case标号,语句序列的执行内容是不同的,每个语句序列允许有一条语句或多条语句组成,但是case中的多条语句不需要按照复合语句的方式处理(用{}将语句括起来),若某一语句序列i为空,则对应的break语句可以省略(去掉)。 17 ④break是中断跳转语句,表示在完成相应的case标号规定的操作之后,不继续执行switch语句的剩余部分而直接跳出switch语句之外,继而执行switch结构后面的第一条语句,如果不在switch结构的case中使用break语句。程序就会接着执行下面的语句。 18 ⑤default用于处理所有switch结构的非法操作。当表达式的值与任何一个case都不匹配时,则执行default语句。 19 20 21 java 1.6(包括)以前,只是支持等价成int 基本类型的数据:byte ,short,char,int(其他的都不可以)。 22 1.7加入的新特性可以支持String类型的数据。 23 long是不可以的。。就算是通过强制的转化也必须是转成int。 24
7. 需求:编写一个5分制的打分系统,5分为优、4分为良、3分为及格、其他为不及格(使用switch语句);
8. 需求:使用递归算法计算1到100相加之和。
1 2 public class Test { 3 4 static int dg(int i) { /* 定义变量 */ 5 int sum; 6 if (i == 1) /* 假设条件 */ 7 return 1; 8 else 9 sum = i + dg(i - 1); /* 1~100的和的表达式 */ 10 return sum; /* 返回结果 */ 11 } 12 13 public static void main(String[] args) { 14 System.out.println(dg(100));//結果5050 15 } 16 } 17 18 ———————————————— 19 版权声明:本文为CSDN博主「capricornce」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。 20 原文链接:https://blog.csdn.net/capricornce/article/details/76679645
9. 数组的声明方式有哪几种,并举例说明,初始化方式有几种并举例说明;
1 一维数组的声明 2 1.数据类型[] 数组名; 3 2.数据类型 数组名[]; 4 一维数组的初始化 5 1.数据类型[] 数组名 = new 数据类型[数组的长度] 6 例一:int[] arr = new int[3]; 7 2.数据类型[] 数组名 ={内容1,内容2,内容3…}; 8 例二:int[] arr={1,2,3,6}; 9 3.数据类型[] 数组名 =new int[]{内容1,内容2,内容3…}; 10 int[] arr=new int[]{1,2,3,4,5,6,7,22}; 11 12 注:如果一个数组赋值给另一个数组,则实质是赋值的地址 13 例:int[] a = {1,2,3};//假如a的地址0x0001 14 int[] b = {12};//假如a的地址0x0002 15 b = a;//这句话就是将b指向0x0001 16 17 二维数组声明 18 1.数据类型[][] 数组名; 19 2.数据类型 数组名[][]; 20 二维数组的初始化 21 1.数据类型[][] 数组名 = new 数据类型[数组的长度][数组的长度]; 22 例: 23 int[][] arr = new int[3][];//最后一个中括号的值可写可不写如果不写的话需要下边的代码进行初始化 24 arr[0] = new int[2]; 25 arr[1] = new int[3]; 26 arr[2] = new int[5]; 27 arr[0][1] = 1;//每个二维数组中的一维数组初始化之后可以用这样的形式进行赋值 28 2.数据类型[] 数组名 ={{内容1,内容2…},{内容1,内容2,内容3…},{内容1,内容2…}}; 29 例:int[] arr={{1,2},{1,2,3},{1,2,3,4,5}}; 30 3.数据类型[][] 数组名 =new int[][]{{内容1,内容2…},{内容1,内容2,内容3…},{内容1,内容2…}}; 31 int[] arr=new int[]{{1,2},{1,2,3},{1,2,3,4,5}}; 32 33 34 ———————————————— 35 版权声明:本文为CSDN博主「chaogu94」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。 36 原文链接:https://blog.csdn.net/chaogu94/article/details/78940757
10. 需求:找出一个int类型数组中的最大数、最小数、重复次数最多的任意一个数;
1 import java.util.HashMap; 2 import java.util.Map.Entry; 3 4 //找出一个int类型数组中的最大数、最小数、重复次数最多的任意一个数 5 public class MaoPao { 6 int tmp = 0; 7 void maxArr(int[]a){ 8 for (int i = 0; i < a.length; i++) { 9 if (tmp<=a[i]) { 10 tmp = a[i]; 11 } 12 } 13 System.out.println("数组中的最大值为"+tmp); 14 15 } 16 void minArr(int[]a){ 17 for (int i = 0; i < a.length; i++) { 18 if (tmp>=a[i]) { 19 tmp = a[i]; 20 } 21 } 22 System.out.println("数组中的最小值为"+tmp); 23 24 } 25 26 public static void main(String[] args) { 27 int a [] = {1,1,1,1,1,1,2,3,-1,-12,54,23}; 28 MaoPao mp = new MaoPao(); 29 mp.maxArr(a);//54 30 mp.minArr(a);//-12 31 HashMap<Integer, Integer> map1 = new HashMap<Integer,Integer>(); 32 //将数组中每个数(key)以及对应的出现次数(value)加入map中 33 for (int i = 0; i < a.length; i++) { 34 if (map1.containsKey(a[i])) { 35 map1.put(a[i], map1.get(a[i])+1); 36 } else { 37 map1.put(a[i], 1); 38 } 39 } 40 int tmp = 0; 41 //求出value的最大值 42 for (int i : map1.keySet()) { 43 if (map1.get(i)>=tmp) { 44 tmp = map1.get(i); 45 } 46 } 47 //最大值对应的key 48 for (int i : map1.keySet()) { 49 if (tmp==map1.get(i)) { 50 System.err.println(i+"出现的次数最多,为"+tmp+"次"); 51 } 52 } 53 } 54 } 55 /**结果 56 数组中的最大值为54 57 数组中的最小值为-12 58 1出现的次数最多,为6次 59 */ 60 ———————————————— 61 版权声明:本文为CSDN博主「裸奔的小强QQ」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。 62 原文链接:https://blog.csdn.net/qq_36184373/article/details/95472879
11. 什么是对象,什么是类。
1 对象是客观存在的事物,可以说任何客观存在的都是可以成为对象,一台电脑,一直钢笔,一个人,一辆轿车等等,都是可以成为对象。 2 3 那么什么是类呢?类是对象的模子,具有相同属性和方法的一组对象的集合,类是不存在的,是用来描述对象信息。在计算机的世界里面,计算机关注的事数据信息,我们描述数据信息的时候一定要要描述数据类型,对象就是具体的数据信息,类是信息的数据类型。 4 5 对象的属性和方法分别表示什么呢?属性是表示对象有什么,方法是表示对象能干什么。 6 7 在类中定义的变量是成员变量,成员变量又称为静态变量和实例变量,静态变量是用static修饰的变量,实例变量也成为是对象变量,类变量,通过对象的引用来访问实例变量。 8 9 在方法中定义的变量是局部变量,他们只存在在{}之间,无法再{之外进行一些操作,比如读取数据,赋值等等。 10 ———————————————— 11 版权声明:本文为CSDN博主「lkx_123」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。 12 原文链接:https://blog.csdn.net/lkx_123/article/details/80559138
12. java的面相对象你如何理解(请用自己理解的方式说明);
1 面向对象是向现实世界模型的自然延伸,这是一种”万物皆对象”的编程思想。在现实生活中的任何物体都可以归为一类事物,而每一个个体都是一类事物的实例。 2 面向对象有三大特性:封装、继承、多态。 3 (1)封装。是将一类事物的属性和行为抽象成一个类,一般是使其属性私有化,行为公开化,提高了数据的隐秘性的同时,使代码模块化。这么做的好处是: 4 ? 将变化隔离。 5 ? 便于使用。 6 ? 提高代码复用性。 7 ? 提高安全性。 8 封装原则: 9 ? 将不需要对外提供的内容都隐藏起来。 10 ? 把属性都隐藏,提供公共方法对其访问。 11 Java中可以通过对类的成员设置一定的访问权限,实现类中成员的信息隐藏。 12 13 private:类中限定为private的成员,只能被这个类本身访问。如果一个类的构造方法声明为private,则其它类不能生成该类的一个实例。 14 default:类中不加任何访问权限限定的成员属于缺省的(default)访问状态,可以被这个类本身和同一个包中的类所访问。 15 protected:类中限定为protected的成员,可以被这个类本身、它的子类(包括同一个包中以及不同包中的子类)和同一个包中的所有其他的类访问。 16 public:类中限定为public的成员,可以被所有的类访问。 17 18 (2)继承。基于已有的类的定义为基础,构建新的类,已有的类称为父类,新构建的类称为子类,子类能调用父类的非private修饰的成员,同时还可以自己添加一些新的成员,扩充父类,甚至重写父类已有的方法,更其表现符合子类的特征。 19 Java中父类可以拥有多个子类,但是子类只能继承一个父类,称为单继承。 20 继承的好处是: 21 ? 实现了代码的复用。 22 ? Java中所有的类都是通过直接或间接地继承java.lang.Object类得到的。 23 ? 子类不能继承父类中访问权限为private的成员变量和方法。 24 ? 子类可以重写父类的方法,即命名与父类同名的成员变量。 25 26 Java中通过super来实现对父类成员的访问,super用来引用当前对象的父类。super 的使用有三种情况: 27 ? 访问父类被隐藏的成员变量,如:super.variable; 28 ? 调用父类中被重写的方法,如:super.Method([paramlist]),super())调用父类构造方法; 29 ? 调用父类的构造函数,如:super([paramlist]); 30 31 super和this的用法相同:this代表本类应用 ;super代表父类引用 。当子父类出现同名成员时,可以用super进行区分 ,子类要调用父类构造函数时,可以使用super语句。 32 在子类覆盖方法中,继续使用被覆盖的方法可以通过super.函数名获取。 33 34 注意: 35 36 1 . 子类中所有的构造函数默认都会访问父类中空参数的构造函数,因为每一个构造函数的第一行都有一条默认的语句 super();子类会具备父类中的数据,所以要先明确父类是如何对这些数据初始化的。当父类中没有空参数的构造函数时,子类的构造函数 必须通过this或者super语句指定要访问的构造函数。 37 38 2 . 覆盖时,子类方法权限一定要大于等于父类方法权限静态只能覆盖静态。父类中的私有方法不可以被覆盖。 39 40 3.被final修饰的类是一个最终类,不可以被继承。 41 被final修饰的方法是一个最终方法,不可以被覆盖。 42 被final修饰的变量是一个常量,只能赋值一次。 43 44 4.内部类只能访问被final修饰的局部变量。 45 (3)多态。方法的重写、重载与动态连接构成多态性。如果说封装和继承是为了使代码重用,那么多态则是为了实现接口重用。多态的一大作用就是为了解耦–为了解除父子类继承的耦合度。如果说继承中父子类的关系式IS-A的关系,那么接口和实现类之之间的关系式HAS-A。简单来说,多态就是允许父类引用(或接口)指向子类(或实现类)对象。很多的设计模式都是基于面向对象的多态性设计的。 46 多态性:发送消息给某个对象,让该对象自行决定响应何种行为。 47 48 通过将子类对象引用赋值给超类对象引用变量来实现动态方法调用。 49 50 java 的这种机制遵循一个原则:当超类对象引用变量引用子类对象时,被引用对象的类型而不是引用变量的类型决定了调用谁的成员方法,但是这个被调用的方法必须是在超类中定义过的,也就是说被子类覆盖的方法。 51 52 1. 如果a是类A的一个引用,那么,a可以指向类A的一个实例,或者说指向类A的一个子类。 53 54 2. 如果a是接口A的一个引用,那么,a必须指向实现了接口A的一个类的实例。要理解多态性,首先要知道什么是“向上转型”。 55 56 子类Cat继承了Animal类,那么后者就是前者是父类。 57 58 Cat c = new Cat();//实例化一个Cat的对象, 59 60 Animal a = new Cat();//定义了一个Animal类型的引用,指向新建的Cat类型的对象 61 由于Cat是继承自它的父类Animal,所以Animal类型的引用是可以指向Cat类型的对象的。那么这样做的什么意义是:因为子类是对父类的一个改进和扩充,所以一般子类在功能上较父类更强大,属性较父类更独特, 62 定义一个父类类型的引用指向一个子类的对象既可以使用子类强大的功能,又可以抽取父类的共性。 63 所以,父类类型的引用可以调用父类中定义的所有属性和方法,但是对于子类中定义而父类中没有的方法,它是无可奈何的; 64 同时,父类中的一个方法只有在在父类中定义而在子类中没有重写的情况下,才可以被父类类型的引用调用; 65 对于父类中定义的方法,如果子类中重写了该方法,那么父类类型的引用将会调用子类中的这个方法,这就是动态连接。 66 实现多态,有二种方式,覆盖(override),重载(overload)。 67 68 覆盖,是指子类重新定义父类的虚函数的做法。它是覆盖了一个方法并且对其重写,以求达到不同的作用。在覆盖要注意以下的几点: 69 1、覆盖的方法的标志必须要和被覆盖的方法的标志完全匹配,才能达到覆盖的效果; 70 2、覆盖的方法的返回值必须和被覆盖的方法的返回一致; 71 3、覆盖的方法所抛出的异常必须和被覆盖方法的所抛出的异常一致,或者是其子类; 72 4、被覆盖的方法不能为private,否则在其子类中只是新定义了一个方法,并没有对其进行覆盖。 73 74 重载,是指允许存在多个同名函数,而这些函数的参数表不同(或许参数个数不同,或许参数类型不同,或许两者都不同)。它是指我们可以定义一些名称相同的方法,通过定义不同的输入参数来区分这些方法,然后再调用时,在使用重载要注意以下的几点: 75 1、在使用重载时只能通过不同的参数样式。例如,不同的参数类型,不同的参数个数,不同的参数顺序(当然,同一方法内的几个参数类型必须不一样,例如可以是fun(int,float),但是不能为fun(int,int)); 76 2、不能通过访问权限、返回类型、抛出的异常进行重载; 77 3、方法的异常类型和数目不会对重载造成影响; 78 4、对于继承来说,如果某一方法在父类中是访问权限是priavte,那么就不能在子类对其进行重载,如果定义的话,也只是定义了一个新方法,而不会达到重载的效果。 79 80 多态也有弊端:当父类引用指向子类对象时,虽然提高了扩展性,但是只能访问父类中具备的方法,不可以访问子类中特有的方法。(前期不能使用后期产生的功能,即访问的局限性) 81 参考文章: 82 ———————————————— 83 版权声明:本文为CSDN博主「依夜知秋」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。 84 原文链接:https://blog.csdn.net/qq_39309971/article/details/81330067
13. 请逐一说明全局变量、局部变量、成员变量、实例变量、静态变量;
1 全局变量 2 全局变量又叫成员变量,它是声明在类里,函数,静态语句块外的变量,全局变量又分为类变量(静态变量)、实例变量两种. 3 通过代码来看一下: 4 5 private int i;//实例变量 6 private static int j;//类变量 7 1 8 2 9 实例变量总是通过对象来访问,因为它们的值在对象和对象之间有所不同。而由static修饰的类变量(静态变量)在类装载的时候就会被初始化,也就是说一处修改多处改变. 10 11 局部变量 12 方法内定义的变量叫局部变量,因为只能在方法内部使用,固不可以用private,public,protect来修饰。 13 14 { 15 int k;//局部变量 16 } 17 1 18 2 19 3 20 类变量 21 类变量:又叫静态变量 用static修饰 它可以直接用类名调用 也可以用对象调用 而且所有对象的同一个类变量都是共享同一块内存空间的. 22 23 实例变量 24 实例变量:不用static修饰 它只能通过对象调用 而且所有对象的同一个实例变量是共享不同的内存空间的. 25
静态变量
是一个修饰符,用于修饰成员(成员变量和成员函数)。
特点:
1、想要实现对象中的共性数据的对象共享。可以将这个数据进行静态修饰。
2、被静态修饰的成员,可以直接被类名所调用。也就是说,静态的成员多了一种调用方式。类名.静态方式。
3、静态随着类的加载而加载。而且优先于对象存在。
弊端:
1、有些数据是对象特有的数据,是不可以被静态修饰的。因为那样的话,特有数据会变成对象的共享数据。这样对事物的描述就出了问题。所以,在定义静态时,必须要明确,这个数据是否是被对象所共享的。
2、静态方法只能访问静态成员,不可以访问非静态成员。
因为静态方法加载时,优先于对象存在,所以没有办法访问对象中的成员。
3、静态方法中不能使用this,super关键字。
因为this代表对象,而静态在时,有可能没有对象,所以this无法使用。
什么时候使用静态变量?
在程序运行期间,类中的静态变量其内存空间对所有该类的实例是共享的,因此在某些时候,为了节省内存空间开销,共享资源, 我们可以将类中的变量声明为静态变量。
但是因为静态变量生命周期太长,并且不易被系统回收,所有如果使用不合理,就会适得其反,从而造成大量内存的浪费。
因此建议在全部符合下列条件的情况下才使用静态变量:
(1)变量所包含的对象体积较大,占用内存较多
(2)变量所包含的对象生命周期较长
(3)变量所包含的对象数据稳定
(4)该类的实例 有 对该变量包含对象的共享需求
————————————————
版权声明:本文为CSDN博主「言曌」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/LIU_YANZHAO/article/details/79429407
26 27 ———————————————— 28 版权声明:本文为CSDN博主「riemann_」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。 29 原文链接:https://blog.csdn.net/riemann_/article/details/93929658
14. 面相对象的三大特征是什么,逐一进行解释并举例说明
;
1 Java面相对象的三大特征:封装,继承,多态; 2 3 一、封装(隐藏成员变量) 4 5 步骤:1.隐藏成员变量。将成员变量加private。 6 7 结果:其他类再创建狗的对象的时候,在调用成员变量时显示错误。 8 9 2.创建公有的getter和setter方法。 10 11 在此类中创建共有的(public) (setName)创建成员变量的赋值方法。 12 13 注意:(1).setName N大写。 14 15 (2).方法的参数必须是成员变量的类型。 16 17 3.在setter和getter加入属性控制。 18 19 4.setter局部变量和成员变量名字相同时。 20 21 5.this 在本类中,调用自己和成员变量和方法。 22 23 特殊方法:1.构造方法:实例化 创建对象并赋值。 24 25 语法:public 类名(){ 26 27 } 28 29 (1)创建类含有无参构造方法。 30 31 (2)创建对象时候就会调用此构造方法。 32 33 (3)构造方法由于方法名相同,传递参数类型不可一致。 34 35 有参(在本类中写) 实例化对象(在他类)setName(); dog.setName(""); 36 37 (4)定义有参购造方法,隐藏的无参构造方法失效。必须在类中定义无参构造方法。 38 39 2.String.format();直接使用类名。 40 41 二、继承 42 43 1.概念。 44 45 减少代码冗余 46 47 是类与类中的关系,is-a关系。 48 49 优点:子类可以拥有父类的所有属性和方法。 50 51 缺点:Java中继承特点:单继承、一个类只有一个父类。 52 53 语法:extends 54 55 2.继承关系初始化顺序 56 57 父类属性--》父类构造方法--》子类属性--》子类构造方法 58 59 3.方法的重载和重写 60 61 重载 overloading 62 63 规则:同一个类中 64 65 方法的名称相同 66 67 参数列表不相同(类型、个数、顺序) 68 69 返回值类型和访问修饰符无关 70 71 重写 override 72 73 规则:继承关系中体现 74 75 方法名字相同 76 77 参数列表必须相同 78 79 返回值的类型相同或者是其子类 80 81 方法重写:相对于继承而言,子类中对父类已经存在的方法进行区别修改。 82 83 4.abstract 抽象类 84 85 会使这个类成为一个抽象类,这个类将不能生成对象实例,可以做为对象变量声明的类型,需要子类继承并覆盖其中的抽象方法。 86 87 5.final 88 89 final:当用final修饰一个类时,表明这个类不能被继承。也就是说,如果一个类你永远不会让他被继承,就可以用final进行修饰。final类中的成员变量可以根据需要设为final,但是要注意final类中的所有成员方法都会被隐式地指定为final方法。 90 三、多态 91 1.生活中的多态 92 93 同一种的事物,由于条件不同,则产生不同的结果,事物的多种表现状态。 94 95 程序中的多态 96 97 同一个类型,使用不同的实力,执行不同的操作。 98 2.发生在继承关系中 99 3.多态实现前提 100 (1)类与类之间存在继承关系。 101 (2)类与接口机之间存在实现关系。 102 4.多态实现步骤 103 (1)编写父类 104 (2)编写子类 105 (3)使用时,就可以使用父类的引用类型,子类的实例。 106 5.多态的实现方式 107 (1)Pet pet=new Dog(); 108 (2)使用父类作为方法的形参实现。 109 (3)使用父类作为返回值。 110 ———————————————— 111 版权声明:本文为CSDN博主「weixin_39469005」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。 112 原文链接:https://blog.csdn.net/weixin_39469005/article/details/81165870
15. 接口和抽象类的区别;
1 接口和抽象类有什么区别 你选择使用接口和抽象类的依据是什么? 2 3 接口和抽象类的概念不一样。接口是对动作的抽象,抽象类是对根源的抽象。 抽象类表示的是,这个对象是什么。接口表示的是,这个对象能做什么。比如,苏格兰折耳猫,布偶猫,这 两个类(如果是类的话??),他们的抽象类是猫。说明,他们都是猫。 猫可以吃东西,耗子也可以吃东西,你可以把“吃东西”定义成一个接口,然后让这些类去实现它. 所以,在高级语言上,一个类只能继承一个类(抽象类)(正如猫不可能同时是生物和非生物),但是可以 实现多个接口(吃饭接口、走路接口)。 第一点.接口是抽象类的变体,接口中所有的方法都是抽象的。而抽象类是声明方法的存在而不去实现它 的类。 第二点.接口可以多继承,抽象类不行 第三点.接口定义方法,不能实现,而抽象类可以实现部分方法。 第四点.接口中基本数据类型为 static 而抽类象不是的。 第五点.Java 接口中声明的变量默认都是 final 的。抽象类可以包含非 final 的变量。 第六点.Java 接口中的成员函数默认是 public 的。抽象类的成员函数可以是 private,protected 或者 是 public。 4 5 当你关注一个事物的本质的时候,用抽象类;当你关注一个操作的时候,用接口。 6 7 抽象类的功能要远超过接口,但是,定义抽象类的代价高。因为高级语言来说(从实际设计上来说也是) 每个类只能继承一个类。在这个类中,你必须继承或编写出其所有子类的 所有共性。虽然接口在功能上会弱化许多,但是它只是针对一个动作的描述。而且你可以在一个类中同时 8 实现多个接口。在设计阶段会降低难度的。 9 10 接口是绝对抽象的,不可以被实例化。抽象类也不可以被实例化 11 ———————————————— 12 版权声明:本文为CSDN博主「正在努力的陈序员」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。 13 原文链接:https://blog.csdn.net/qq_42780864/article/details/81489040
16. 什么是构造方法,说明其特征及作用,什么是构造函数重载;
1 当新对象被创建的时候,构造函数会被调用。每一个类都有构造函数。在程序员没有提供构造函数的情况下,Java编译器会为这个类创建一个默认的构造函数。 2 3 Java中的构造函数重载和方法重载很类似,可以为一个类创建多个构造函数。每一个构造函数都必须有它自己唯一的参数列表
17. 什么是方法重写,什么是方法重载;
1 java中的方法重写与方法重载 2 一、方法重载 3 ? 方法重载主要是指,其方法要实现的功能一样,但是需要的参数类型和个数不同,需要进行方法重载; 4 5 ? 重载的方法的参数值列表不相同,例如: 6 7 public int add(int a, int b) { 8 return a + b; 9 } 10 11 public int add(int a, int b, int c) { 12 return a + b + c; 13 } 14 1 15 2 16 3 17 4 18 5 19 6 20 7 21 二、方法重写 22 ? 方法重写的思想:子类对父类的功能实现不满意,想要覆盖,或者说扩展,就使用方法重写 23 24 1、定义:子类中出现了和父类中一模一样的方法声明(方法名,参数列表,返回值类型),也被称为方法覆盖,方法复写。 25 2、重写的注意事项: 26 ? A.父类私有的方法子类不能重写,因为私有的方法,子类都不能继承,就更不可能被重写! 27 ? B.子类在重写父类方法时,子类方法前面的权限修饰符,不能比父类的低,要比父类的高,或一样 28 权限修饰符:public>protected>缺省的>private 29 ? C.构造方法,没有重写这么一说,构造方法不能重写 30 ? D.静态方法不参与重写:父类的静态方法是父类的,子类的静态方法是子类的,就算他俩的静态方法名称是一样的,也不算是方法重写,各有各的归属! 31 32 3、重写父类方法的快捷键 33 ? ctrl + o(字母O); 34 35 public class MyTest3 { 36 37 } 38 39 class Fu { 40 public void show() { 41 System.out.println("fu show"); 42 } 43 } 44 45 class Zi extends Fu { 46 //Ctrl+O 重写父类的方法 47 @Override //注解:@Override 检测这个方法,是不是重写父类的 48 public void show() { 49 50 } 51
18. 参数的传递:说明基本数据类型的传递和引用数据类型传递
1 ava中数据类型分两种:基本数据类型和引用数据类型 2 基本数据类型有:整型类型的数据(byte、short 、int 、long )浮点型、字符型、布尔型 3 byte:Java中最小的数据类型,在内存中占8位(bit),即1个字节,取值范围-128~127,默认值0 4 5 short:短整型,在内存中占16位,即2个字节,取值范围-32768~32717,默认值0 6 7 int:整型,用于存储整数,在内在中占32位,即4个字节,取值范围-2147483648~2147483647,默认值0 8 9 long:长整型,在内存中占64位,即8个字节-2^63~2^63-1,默认值0L 10 11 float:浮点型,在内存中占32位,即4个字节,用于存储带小数点的数字(与double的区别在于float类型有效小数点只有6~7位),默认值0 12 13 double:双精度浮点型,用于存储带有小数点的数字,在内存中占64位,即8个字节,默认值0 14 15 char:字符型,用于存储单个字符,占16位,即2个字节,取值范围0~65535,默认值为空 16 17 boolean:布尔类型,占1个字节,用于判断真或假(仅有两个值,即true、false),默认值false 18 19 引用数据类型(数组、类、接口类等): 20 Java语言本身不支持C++中的结构(struct)或联合(union)数据类型,它的复合数据类型一般都是通过类或接口进行构造,类提供了捆绑数据和方法的方式,同时可以针对程序外部进行信息隐藏。 21 22 基本数据类型引用传递参数和引用类型传递参数是有区别的(看一个例子): 23 public class arrayTest { 24 25 public static void main(String[] args) { 26 int a=1; 27 test(a); 28 System.out.println(a); 29 30 31 } 32 static void test(int b) 33 { 34 b=100; 35 } 36 1 37 2 38 3 39 4 40 5 41 6 42 7 43 8 44 9 45 10 46 11 47 12 48 13 49 } 50 这是一个基本数据类型int整型的传参,输出变量a的值发现a仍然是1,并没有发生任何改变;虽然在调用test函数的时候,执行了a=100,但是a的值确实没有改变 51 52 public class arrayTest { 53 54 public static void main(String[] args) { 55 //引用数据类型传参 56 int[] arr=new int[]{1,2,3}; 57 test(arr); 58 System.out.println(Arrays.toString(arr)); 59 60 61 } 62 static void test(int[] arr) 63 { 64 arr[2]=100; 65 } 66 1 67 2 68 3 69 4 70 5 71 6 72 7 73 8 74 9 75 10 76 11 77 12 78 13 79 14 80 } 81 82 这是一个引用数据类型传参,在函数体内对arr[2]进行了重新赋值,在调用该函数之后重新输出数组,发现数组内的值也发生了改变,这跟基本数据类型的结果是有区别的 83 84 原因是什么呢 85 当基本数据类型作为传递参数的时候,传的就是参数的具体值,这里变量的值确实发生了改变,它是存储在栈里边的,出了函数体就销毁了;变量a跟变量b是两个完全不同的变量;而当引用数据类型传递参数的时候,传递的是对象的首地址,也就是又新建了一个栈内的对象,指向堆内的一块内存,形参变量和实参变量共享同一块堆区; 86 87 88 ———————————————— 89 版权声明:本文为CSDN博主「little_kkk」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。 90 原文链接:https://blog.csdn.net/qq_39497607/article/details/81385051
19. 内部类:编写局部内部类、静态内部类、匿名内部类
1 1 内部类的概念 2 内部类是定义在另一个类中的类;下面类B是类A的内部类。即内部类对象引用了实例化该内部对象的外围类对象。 3 4 public class A{ 5 class B {} 6 } 7 1 8 2 9 3 10 2 为什么需要内部类?(来自JAVA核心技术) 11 内部类方法可以访问该类定义所在的作用域中的数据,包括私有数据。 12 内部类可以对同一个包中的其他类隐藏起来。 13 当想要定义一个回调函数且不想编写大量代码时,使用匿名内部类比较便捷。 14 3 内部类的分类 15 3.1 成员内部类 16 成员内部类:存在于某个类的内部,与全局属性或者方法同级的内部类就是成员内部类。 17 成员内部类特点: 18 19 成员内部类可以无条件访问外部类的所有成员属性和成员方法(包括静态成员和私有成员)。 20 成员内部类和外部类的属性和方法名同名时,外部类的属性和方法会隐藏;但可以通过外部类.this.成员变量的方式访问外部类的属性和方法。 21 外部类必须通过成员内部类的对象来访问内部类的属性和方法。 22 成员内部类对象会隐式的引用一个外部类对象。(可以解释第一点) 23 成员内部类可以有public\private\protected以及默认访问权限。 24 成员内部类实例: 25 26 public class Person{ 27 public void eat(){} 28 public class DoWork implements Work{} 29 } 30 1 31 2 32 3 33 4 34 3.2 局部内部类 35 局部内部类:是定义在一个方法或者一个作用域里面的类。它与成员内部类的区别在于局部内部类的访问仅在于方法内或者作用域内。 36 局部内部类的特点: 37 38 不能有private、public、protected和static等修饰符,与局部变量类似。 39 只能在定义局部内部类的方法或者作用域中实例化; 40 局部内部类的对象不能使用该内部类所在方法或者作用域的非final局部变量(为什么?); 41 局部内部类实例: 42 43 public class Person{ 44 public void eat(){ 45 public class DoWork implements Work{} 46 } 47 } 48 1 49 2 50 3 51 4 52 5 53 3.3 匿名内部类 54 匿名内部类:不定义类的名字,在使用的地方直接定义对象。 55 匿名内部类的特点: 56 57 唯一一种没有构造器的类;匿名内部类在编译时,编译器会自动起名xxx$1.class; 58 匿名内部类不能存在任何静态的变量、方法等; 59 匿名内部类是局部内部类的特例; 60 大部分匿名内部类用于接口返回; 61 匿名内部类实例: 62 63 public class Person{ 64 public DoWork doSomething(){ 65 return new DoWork(){ 66 public void do(){} 67 } 68 } 69 } 70 1 71 2 72 3 73 4 74 5 75 6 76 7 77 3.4 静态内部类 78 静态内部类:在成员内部类的基础上加上一个static关键字就是静态内部类。 79 静态内部类的特点: 80 81 不需要依赖外部类。 82 不能使用外部类的非静态属性和方法。 83 静态内部类实例: 84 85 public class Person{ 86 public void eat(){} 87 public static class DoWork implements Work{} 88 } 89 ———————————————— 90 版权声明:本文为CSDN博主「Starry-」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。 91 原文链接:https://blog.csdn.net/nobody_1/article/details/90886330
20. 最终类的特征;
1 最终类 2 使用关键字 final 对类进行修饰. 3 4 [访问控制符] final class 类名 { 类体} 5 6 例如: 7 8 public final class MyClass{ ... } 9 10 说明: 11 12 final 不能当做父类, 不能被继承,不能有子类 , 只能被实例化对象 . 13 如果认为封装类中的某些数据(成员变量) 或者 某些方法(成员方法) 不能被子类隐藏或者重写, 可以将这个方法或变量用final 修饰. 最常见的比如 String 类. 14 如果 final 修饰父类中的一个方法 , 那么这个方法不能被子类重写 . 15 final 类中的成员可以 都是普通 的成员变量或者方法 ,也就是说可以不用final 修饰. 16 public class Test3_20 { 17 18 public static void main(String[] args) { 19 // TODO Auto-generated method stub 20 MyFinalClass mfc = new MyFinalClass() ; 21 System.out.println(""+mfc.getArea(4.5)); 22 mfc.shout("哈哈"); 23 } 24 25 } 26 public final class MyFinalClass { 27 28 public final double MYPI = 3.1415 ; 29 public double getArea(final double radius) { 30 return MYPI * radius * radius ; 31 } 32 public final void shout(String s) { 33 System.out.println(s); 34 } 35 } 36 37 ———————————————— 38 版权声明:本文为CSDN博主「不想悲伤到天明」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。 39 原文链接:https://blog.csdn.net/qq_41661809/article/details/88601821
21. final 和finally 的区别;
1 final与finally的却别 2 3 先说final 4 5 final可修饰: 6 7 1.修饰变量 8 9 2.修饰方法 10 11 3.修饰类 12 13 首先来看第一种情况,如果final修饰的是一个基本类型,就表示这个变量被赋予的值是不可变的,它是个常量, final在修饰方法的传入参数时,则传入参数时不可修改的; 14 如果final修饰的是一个对象,就表示这个变量被赋予的引用是不可变的,这里这个不可改变的只是这个变量所保存的引用,并不是这个引用所指向的对象。 15 16 在final修饰方法时,方法是不可以被该类的子类所继承的. 17 在final修饰类是,被修饰的类是不可以被继承的 18 19 被fianl修饰的变量必须被初始化,初始化的方式有: 20 21 1.在定义的时候初始化 22 23 2.在构造器中初始化,但静态的final是不可以的 24 25 3.final变量可以在构造块中初始化,如果是静态的就不能再非静态的构造块中初始化 26 27 代码验证: 28 29 .public class Test { 30 . // 在定义时初始化 31 . public final int A = 10; 32 . 33 . public final int B; 34 . // 在初始化块中初始化 35 . { 36 . B = 20; 37 . } 38 . 39 . // 非静态final变量不能在静态初始化块中初始化 40 . // public final int C; 41 . // static { 42 . // C = 30; 43 . // } 44 . 45 . // 静态常量,在定义时初始化 46 . public static final int D = 40; 47 . 48 . public static final int E; 49 . // 静态常量,在静态初始化块中初始化 50 . static { 51 . E = 50; 52 . } 53 . 54 . // 静态变量不能在初始化块中初始化 55 . // public static final int F; 56 . // { 57 . // F = 60; 58 . // } 59 . 60 . public final int G; 61 . 62 . // 静态final变量不可以在构造器中初始化 63 . // public static final int H; 64 . 65 . // 在构造器中初始化 66 . public FinalTest() { 67 . G = 70; 68 . // 静态final变量不可以在构造器中初始化 69 . // H = 80; 70 . 71 . // 给final的变量第二次赋值时,编译会报错 72 . // A = 99; 73 . // D = 99; 74 . } 75 . 76 . // final变量未被初始化,编译时就会报错 77 . // public final int I; 78 . 79 . // 静态final变量未被初始化,编译时就会报错 80 . // public static final int J; 81 .} 82 83 84 85 finally语句? 86 87 finally就比较简单了,它只能用在try/catch语句中,并且附带着一个语句块,表示这段语句最终总是被执行。 88 即使在try语句中有return等结束方法或循环的代码被执行后,finally中的内容仍然会被执行 89 90 public class Test2{ 91 public static void main(String[] args){ 92 try{ 93 System.out.println("return之前!"); 94 return; 95 System.out.println("return之后!"); 96 }catch(Exception e){ 97 System.out.println("程序抛出了异常"); 98 }finally{ 99 . System.out.println("finally被执行了!"); 100 } 101 } 102 } 103 运行结果: 104 return之前! 105 106 finally被执行了! 107 108 从结果上我们看到finally中的代码被执行,即使程序被return中断,这是因为return的返回并没有彻底返回,而是在finally中的语句执行完后,彻底返回,结束 109 ———————————————— 110 版权声明:本文为CSDN博主「Kitty__Long」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。 111 原文链接:https://blog.csdn.net/qq120074791/article/details/76409072
22. 请说明访问控制符有哪些,并说明他的作用域(可访问性);
1 访问控制符的作用是说明被声明的内容(类、属性、方法和构造方法)的访问权限,就像发布的文件一样,在文件中标注机密,就是说明该文件可以被哪些人阅读。 2 访问控制在面向对象技术中处于很重要的地位,合理的使用访问控制符,可以通过降低类和类之间的耦合性(关联性)来降低整个项目的复杂度,也便于整个项目的开发和维护。具体的实现就是通过访问控制符将类中会被其它类调用的内容开放出来,而把不希望别人调用的内容隐藏起来,使一个类开放的信息变得比较有限,从而降低了整个项目开放的信息,另外因为不被别人调用的功能被隐藏起来,在修改类内部隐藏的内容时,只要最终的功能没有改变,即使改变功能的实现方式,项目中其它的类不需要更改,这样可以提高了代码的可维护性,便于项目代码的修改。 3 4 在Java语言中访问控制权限有4种,使用三个关键字进行表达,依次如下: 5 6 l public——公共的 7 8 l protected——受保护的 9 10 l 无访问控制符——默认的 11 12 l private——私有的 13 14 其中无访问控制符是指不书写任何的关键字,也代表一种访问权限,访问控制符的使用示例如下所示: 15 16 public class AccessControl { 17 18 int n; 19 20 public AccessControl(){ 21 22 init(); 23 24 } 25 26 private void init(){} 27 28 protected void test(int k){} 29 30 } 31 32 该示例代码中演示了各个访问控制符的实际使用示例,其中属性n的访问控制符就是默认的(没有书写关键字)。 33 34 在实际使用时,类声明的访问控制符只有2个:public和无访问控制符,属性声明、构造方法声明和方法声明的访问控制符可以是以上4种中的任何一个。 35 36 这4个访问控制符的权限作用如下表所示: 37 38 作用域 当前类 同一package 子类 其他package 39 40 public √ √ √ √ 41 42 protected √ √ √ × 43 44 无控制符 √ √ × × 45 46 private √ × × × 47 48 在4种访问控制中,public一般称作公共权限,其限制最小,也可以说没有限制,使用public修饰的内容可以在其它所有位置访问,只要能访问到对应的类,就可以访问到类内部public修饰的内容,一般在项目中开放的方法和构造方法使用public修饰,开放给项目使用的类也使用public修饰。protected一般称作继承权限,使用protected修饰的内容可以被同一个包中的类访问也可以在不同包内部的子类中访问,一般用于修饰只开放给子类的属性、方法和构造方法。无访问控制符一般称作包权限,无访问控制符修饰的内容可以被同一个包中的类访问,一般用于修饰项目中一个包内部的功能类,这些类的功能只是辅助其它的类实现,而为包外部的类提供功能。private一般称作私有权限,其限制最大,类似于文件中的绝密,使用private修饰的内容只能在当前类中访问,而不能被类外部的任何内容访问,一般修饰不开放给外部使用的内容,修改private的内容一般对外部的实现没有影响。 49 50 下面以两个基本的示例来说明访问控制符在实际项目中的使用方式。 51 52 第一个使用示例:在项目中,一般不会将类的属性开放给其它的类,也就是不允许外部的类直接访问属性,而是使用对应的存取方法来进行访问。例如在学校的学员管理系统中,需要实现的学生类,按照访问控制符的一般使用规则,实现的代码如下: 53 54 55 56 public class Student { 57 58 59 60 private int age; 61 62 63 64 private int id; 65 66 public int getAge() { 67 68 return age; 69 70 } 71 72 public void setAge(int age) { 73 74 if(age < 0){ 75 76 //处理代码,未实现 77 78 } 79 80 this.age = age; 81 82 } 83 84 public int getId() { 85 86 return id; 87 88 } 89 90 public void setId(int id) { 91 92 //校验id是否合法的代码,未实现 93 94 this.id = id; 95 96 } 97 98 } 99 100 通过将属性的访问权限设定为private,限制所有类外部对属性的访问,而为了让外部可以访问这些属性,专门声明对应的get/set方法来读取/存储数据,这样在设置属性值的set方法中,可以对于参数做出基本的校验,在上面的示例代码中,留出了校验参数的位置,具体的代码未在示例代码中实现。 101 102 第二个使用示例:在项目中,一般为了设计的需要实现一些特定的功能,下面介绍一下使用访问控制符实现的一个功能——使一个类既不能创建对象也不能被继承。实现的方法如下:该类中只实现一个构造方法,而且将该构造方法的访问权限设置为私有的。具体实现代码如下: 103 104 105 106 public class PrivateDemo { 107 108 private PrivateDemo(){} 109 110 } 111 112 在该示例中,PrivateDemo类只有一个构造方法,且该构造方法为私有。按照以前的介绍,创建对象时需要调用构造方法,而private修饰的构造方法无法在类的外部进行访问,所以无法创建对象。另外,在子类的构造方法中也需要调用父类的构造方法,由于private的构造方法无法得到调用,所以该类也不能被继承。
23. static关键字的解释和说明;
1 static关键字可以用来修饰类的变量,方法和内部类。static是静态的意思,也是全局的意思它定义的东西,属于全局与类相关,不与具体实例相关。就是说它调用的时候,只是ClassName.method(),而不是new ClassName().method()。new ClassName()不就是一个对象了吗?static的变量和方法不可以这样调用的。它不与具体的实例有关 2 3 前一阵子有同学问了,main()是什么意思啊?main()的前面不是也有一个static吗,它也是静态方法。它是程序的入口点,就是说java的程序是由java虚拟机执行的,java语言和虚拟机的入口就是main()。因为它是static的,这可以使JVM不创建实例对象就可以运行该方法。因此我们在main()中调用别的类的非静态方法,就要创建实例 4 5 6 static是说这个方法或者变量是静态的,长驻内存的,可以直接访问,而不必实例化的(实例化就是new一个类,也就是在内存中开一个区域)。 7 final是指最终的意思,也就是这个方法或者变量是固定的,不再变动的,绝大多数用来修饰常量的。 8 9 2者没有联系,可以同时用,也可以单独使用一个,也可以2个都不用。
24. 什么是异常?异常的种类?异常的处理机制?
1 Java 中异常分为哪些种类: 2 按照异常需要处理的时机分为编译时异常(也叫强制性异常)也叫 CheckedException 和运行时异常 3 (也叫非强制性异常)也叫 RuntimeException。如果程序没有处理 Checked 异常,该程序在编译时就会发生错误无法编译。这体现了 Java 的设计哲学:没有完善错误处理的代码根本没有机会被执行。 4 5 对 Checked 异常处理方法有两种: 6 1 当前方法知道如何处理该异常,则用 try…catch 块来处理该异常。 7 2 当前方法不知道如何处理,则在定义该方法是声明抛出该异常。 8 9 运行时异常只有当代码在运行时才发行的异常,编译时不需要 try catch。Runtime 如除数是 0 和数组下标越界等,其产生频繁,处理麻烦,若显示申明或者捕获将会对程序的可读性和运行效率影响很大。所以由系统自动检测并将它们交给缺省的异常处理程序。当然如果你有处理要求也可以显示捕获它们。 10 11 Java异常处理机制: 12 Java 对异常进行了分类,不同类型的异常分别用不同的 Java 类表示,所有异常的根类为 java.lang.Throwable,Throwable 下面又派生了两个子类:Error 和 Exception。 13 14 Error 表示应用程序本身无法克服和恢复的一种严重问题。 15 Exception 表示程序还能够克服和恢复的问题,其中又分为系统异常和普通异常, 16 17 系统异常是软件本身缺陷所导致的问题,也就是软件开发人员考虑不周所导致的问题,软件使用者无法克服和恢复这种问题,但在这种问题下还可以让软件系统继续运行或者让软件死掉,例如,数组脚本越界(ArrayIndexOutOfBoundsException),空指针异常(NullPointerException)、类转换异常(ClassCastException); 18 19 普通异常是运行环境的变化或异常所导致的问题,是用户能够克服的问题,例如,网络断线,硬盘空间不够,发生这样的异常后,程序不应该死掉。 20 21 java 为系统异常和普通异常提供了不同的解决方案,编译器强制普通异常必须 try…catch 处理或用 throws 声明继续抛给上层调用方法处理,所以普通异常也称为 checked 异常,而系统异常可以处理也可以不处理,所以,编译器不强制用 try…catch 处理或用 throws 声明,所以系统异常也称为 unchecked 异常 22 23 24 ———————————————— 25 版权声明:本文为CSDN博主「张起灵sy」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。 26 原文链接:https://blog.csdn.net/weixin_44367067/article/details/86287236
25. 区分运行时异常和检查异常的区别?
1 一、什么是异常 :在程序定义中一般指不期而至的各种状况,如:文件找不到、网络连接失败、非法参数等。异常是一个事件,它发生在程序运行期间、或者代码编译时候,它干扰了正常的程序指令流程继续下去。Java通 过API中Throwable类的众多子类描述各种不同的异常。因而,Java异常都是对象,是Throwable子类的实例,描述了出现在一段编码中的 错误条件。当条件生成时,错误将引发异常。 2 在java api中的Throwable类结构如下: 3 4 由其结构图可以看出,所有的异常都继承了父类Throwable。 5 二、 Throwable: 有两个重要的子类:Exception(异常)和 Error(错误),二者都是 Java 异常处理的重要子类,各自都包含大量子类。 6 Error:是程序无法处理的错误,表示运行应用程序中较严重问题。大多数错误与代码编写者执行的操作无关,而表示代码运行时 JVM出现的问题。例如,Java虚拟机运行错误(Virtual MachineError),当 JVM 不再有继续执行操作所需的内存资源时,将出现 OutOfMemoryError。这些异常发生时,Java虚拟机(JVM)一般会选择线程终止。 7 这些错误表示故障发生于虚拟机自身、或者发生在虚拟机准备加载时、或者发生在虚拟机试图执行应用时,如Java虚拟机运行错误(Virtual MachineError)、类定义错误(NoClassDefFoundError)等。这些错误是不可查的,因为它们在应用程序的控制和处理能力之 外,而且绝大多数是程序运行时不允许出现的状况。对于设计合理的应用程序来说,即使确实发生了错误,本质上也不应该试图去处理它所引起的异常状况。在 Java中,错误通过Error的子类描述。 8 9 三、Exception(异常):是程序本身可以处理的异常。 10 Exception 类有一个重要的子类 RuntimeException。RuntimeException 类及其子类表示“JVM 常用操作”引发的错误。例如,若试图使用空值对象引用、除数为零或数组越界,则分别引发运行时异常(NullPointerException、ArithmeticException)和 ArrayIndexOutOfBoundException。 11 注意:异常和错误的区别:异常能被程序本身可以处理,错误是无法处理。 12 13 通常,Java的异常(包括Exception和Error)分为可查的异常(checked exceptions)和不可查的异常(unchecked exceptions)。 14 可查异常(编译器要求必须处置的异常):正确的程序在运行中,很容易出现的、情理可容的异常状况。可查异常虽然是异常状况,但在一定程度上它的发生是可以预计的,而且一旦发生这种异常状况,就必须采取某种方式进行处理。 15 16 除了RuntimeException及其子类以外,其他的Exception类及其子类都属于可查异常。这种异常的特点是Java编译器会检查它,也就是说,当程序中可能出现这类异常,要么用try-catch语句捕获它,要么用throws子句声明抛出它,否则编译不会通过。 17 18 不可查异常(编译器不要求强制处置的异常):包括运行时异常(RuntimeException与其子类)和错误(Error)。 19 20 Exception 这种异常分两大类运行时异常和非运行时异常(编译异常)。程序中应当尽可能去处理这些异常。 21 22 运行时异常:都是RuntimeException类及其子类异常,如NullPointerException、IndexOutOfBoundsException。这些异常是不检查异常,程序中可以选择捕获处理,也可以不处理。这些异常一般是由程序逻辑错误引起的,可以从逻辑角度出发去处理,尽可能避免这类异常的发生。 23 24 运行时异常的特点是Java编译器不会检查它,也就是说,当程序中可能出现这类异常,即使没有用try-catch语句捕获它,也没有用throws子句声明抛出它,也会编译通过。 25 编译异常 (非运行时异常):是RuntimeException以外的异常,类型上都属于Exception类及其子类。从程序语法角度讲是必须进行处理的异常,如果不处理,程序就不能编译通过。如IOException、SQLException等以及用户自定义的Exception异常,一般情况下不自定义检查异常。 26 27 四、 在 Java 应用程序中,异常处理机制为:抛出异常,或者捕捉异常。 28 Java语法规定:对于可查异常必须捕捉、或者声明抛出。允许忽略不可查的RuntimeException和Error。 29 30 五、一些常见的异常类 31 1). runtimeException子类: 32 33 1、 java.lang.ArrayIndexOutOfBoundsException 34 数组索引越界异常。当对数组的索引值为负数或大于等于数组大小时抛出。 35 2、java.lang.ArithmeticException 36 算术条件异常。譬如:整数除零等。 37 3、java.lang.NullPointerException 38 空指针异常。当应用试图在要求使用对象的地方使用了null时,抛出该异常。譬如:调用null对象的实例 39 方法、 访问null对象的属性、计算null对象的长度、使用throw语句抛出null等等 40 4、java.lang.ClassNotFoundException 41 找不到类异常。当应用试图根据字符串形式的类名构造类,而在遍历CLASSPAH之后找不到对应名称的class 42 文件时, 抛出该异常。 43 5、java.lang.NegativeArraySizeException 数组长度为负异常 44 45 6、java.lang.ArrayStoreException 数组中包含不兼容的值抛出的异常 46 47 7、java.lang.SecurityException 安全性异常 48 49 8、java.lang.IllegalArgumentException 非法参数异常 50 1 51 2 52 3 53 4 54 5 55 6 56 7 57 8 58 9 59 10 60 11 61 12 62 13 63 14 64 15 65 16 66 17 67 2).IOException 68 69 IOException:操作输入流和输出流时可能出现的异常。 70 71 EOFException 文件已结束异常 72 73 FileNotFoundException 文件未找到异常 74 1 75 2 76 3 77 4 78 5 79 其他 80 ClassCastException 类型转换异常类 81 82 ArrayStoreException 数组中包含不兼容的值抛出的异常 83 84 SQLException 操作数据库异常类 85 86 NoSuchFieldException 字段未找到异常 87 88 NoSuchMethodException 方法未找到抛出的异常 89 90 NumberFormatException 字符串转换为数字抛出的异常 91 92 StringIndexOutOfBoundsException 字符串索引超出范围抛出的异常 93 94 IllegalAccessException 不允许访问某类异常 95 IllegalStateException 客户端响应异常 96 1 97 2 98 3 99 4 100 5 101 6 102 7 103 8 104 9 105 10 106 11 107 12 108 13 109 14 110 15 111 16 112 除了Java中定义的几种异常,我们也可以自定义异常,自定义的异常字需要继承Exception类即可。 113 如下: 114 115 package com.wlgdo.webiot.exceptions; 116 117 /** 118 * @author : Ligang.Wang[[email protected]] 119 * @date : 2019/3/19 120 */ 121 122 public class RpcException extends Exception { 123 124 String exceptionMsg; // 定义String类型变量 125 126 public RpcException(String exceptionMsg) { 127 exceptionMsg = exceptionMsg; 128 } 129 130 public String getMexceptionMsg() { 131 return exceptionMsg; 132 } 133 } 134 1 135 2 136 3 137 4 138 5 139 6 140 7 141 8 142 9 143 10 144 11 145 12 146 13 147 14 148 15 149 16 150 17 151 18 152 19 153 154 ———————————————— 155 版权声明:本文为CSDN博主「[email protected]肥肥」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。 156 原文链接:https://blog.csdn.net/LeegooWang/article/details/88646008
26. throw和throws的区别?
1 throw: 2 3 表示方法内抛出某种异常对象 4 如果异常对象是非 RuntimeException 则需要在方法申明时加上该异常的抛出 即需要加上 throws 语句 或者 在方法体内 try catch 处理该异常,否则编译报错 5 执行到 throw 语句则后面的语句块不再执行 6 throws: 7 8 方法的定义上使用 throws 表示这个方法可能抛出某种异常 9 需要由方法的调用者进行异常处理 10 ———————————————— 11 版权声明:本文为CSDN博主「ConstXiong」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。 12 原文链接:https://blog.csdn.net/meism5/article/details/90414147
27. String和StringBuffer的区别?
1 相同点: 2 3 都可以储存和操作字符串 4 都使用 final 修饰,不能被继承 5 提供的 API 相似 6 区别: 7 8 String 是只读字符串,String 对象内容是不能被改变的 9 StringBuffer 和 StringBuilder 的字符串对象可以对字符串内容进行修改,在修改后的内存地址不会发生改变 10 StringBuilder 线程不安全;StringBuffer 线程安全 11 12 ———————————————— 13 版权声明:本文为CSDN博主「ConstXiong」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。 14 原文链接:https://blog.csdn.net/meism5/article/details/103135574
28. 需求:编写一个5位数的验证码,要求5个数字不能一样;
1 import java.util.Random; 2 3 public class TEST1 { 4 public static void main(String[] args) { 5 //生成5位随机数 6 //1.找出所有的字符 7 String str = "ABCDEFGHIJKLMNOPQRSJUVWXYZ"; 8 str.toLowerCase(); 9 String str1 = "0123456789"; 10 str = str + str.toLowerCase(); 11 str += str1; 12 System.out.println(str); 13 14 //2.生成字符中的随机一个数 15 /*int R = new Random().nextInt(str.length()); 16 System.out.println(str.charAt(R)); 17 System.out.println("-----------");*/ 18 //3.进行5次循环 19 StringBuilder sb = new StringBuilder(5); 20 for(int i = 0; i < 5; i++){ 21 int R = new Random().nextInt(str.length()); 22 char ch = str.charAt(R);//获取位置 23 System.out.println(str.charAt(R)); 24 sb.append(ch); 25 } 26 System.out.println("-----------------"); 27 System.out.println(sb); 28 } 29 } 30 ———————————————— 31 版权声明:本文为CSDN博主「xiaoblank」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。 32 原文链接:https://blog.csdn.net/xiaoblank/article/details/81675883
29. 说明javabean的特征;(User类:userName,password,phone,address)
1 JavaBean1.0指定的组件模型规定了Bean的如下特征: 2 3 (1)内省:使组件可以发表其支持的操作和属性的机制,也是支持在其他组件中(如Bean的开发工具)发现这种机制的机制。 4 5 (2)属性:在设计Bean时可以改变的外观和行为特征。开发工具通过对Bean进行内省来获知其属性,进而发布其属性。 6 7 (3)定制:Bean通过发布其属性使其可以在设计时被定制。有两种方法支持定制:通过使用Beans的属性编辑器,或者是使用更复杂Bean定制器。 8 9 (4)通信:Bean之间通过事件互相通信。开发工具可以检测一个Bean可以接收和引发的事件。 10 11 (5)持续:使Bean可以存储和恢复其状态。一个Bean的属性被修改以后,可以通过对象的持续化机制保存下来,并可以在需要的时候恢复。 12 13 ———————————————— 14 版权声明:本文为CSDN博主「杨宝涛」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。 15 原文链接:https://blog.csdn.net/yangtao2076/article/details/12249155
30. 请说明你知道的集合有哪些?并逐一说明他们的特性和区别?(list set map分别有哪些说明他的特征)
1 1层中最底层只有ArrayList,跟vector比较它是线程不安全的,数组长度增长率为50%,插入删除没有linkedlist快,但是查找速度快,2层为serializable,cloneable和randomaccess都表示标记接口,serializable主要用于序列化,cloneable作用为复制,要注意用的情况,因为会把地址访问也复制,所以就是会出现一种情况是复制出来和原来的相关联的,谨慎使用,randomaccess用于使算法在随机和顺序访问的list中表现的更加高效(Collections中有一个方法),3层是ArrayList继承的一个抽象类abstractlist类,子类必须实现的方法为get方法因为为抽象方法,4层为abstractcollection抽象类以及abstractlist的父级类层和list接口类已经ArrayList的直接实现类,5层为collection根接口类同时也是abstractcollection抽象类的实现类和list接口类的继承类,6层为iterable接口类,也是collection接口类的继承类,主要用于遍历集合类的接口类,所有集合类都实现了此类。 2 ———————————————— 3 版权声明:本文为CSDN博主「waves6248」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。 4 原文链接:https://blog.csdn.net/waves6248/article/details/87361451
1 stack和vector,是stack为栈先进后出,然后是stack是继承实现类vector的,vector和stack都是数组类型的,但不同的是vector向量类实现了动态数组,他相比于ArrayList是他的两倍,因为他是100%,而且相对于ArrayList的另一个好处是线程更加安全。 2 ———————————————— 3 版权声明:本文为CSDN博主「waves6248」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。 4 原文链接:https://blog.csdn.net/waves6248/article/details/87361451
1 linkedlist,Deque和queue都是接口,是一个队列类似,但是区别是queue是头部删除,尾部添加,而Deque接口是继承queue接口的,他另外支持双向检索和插入元素,相信我们注意到linkedlist少实现了randomassess接口标记,意思是不支持快速算法,因为他虽然相对于ArrayList插入和删除是快速的,但是查找是相对于较慢的,另外还继承了abstractsequentiallist抽象类,他是linkedlist的父类是只支持按次序访问,而不像abstractlist随机访问。 2 ———————————————— 3 版权声明:本文为CSDN博主「waves6248」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。 4 原文链接:https://blog.csdn.net/waves6248/article/details/87361451
1 LinkedHashSet实现类,它是继承HashSet实现类的其实本质上他们两是一样的,但是linkedHashSet在存储数据的时候将顺序也保存了下来,可以按照插入顺序和访问顺序进行迭代,而且它们底层分别靠hashmap和LinkedHashMap去保存数据,往上HashSet的父类为abstractset抽象类,abstractset类又继承了abstractcollection抽象类,它实现了set中绝大部分的函数为set实现类提供了便利,最后是讲一下set接口,它的实现类就是HashSet和linkedHashSet,它是和list接口同级的接口,它和list接口不同的是,他无顺序,不重复,唯一性。 2 ———————————————— 3 版权声明:本文为CSDN博主「waves6248」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。 4 原文链接:https://blog.csdn.net/waves6248/article/details/87361451
1 集合中TreeSet实现类的依赖图系,它和HashSet实现类还是有很大区别的,我们都知道一说到set接口我们可能就会想到无序,不重复对吧,而且我在讲HashSet的时候也有提到过,但是可以从图中看出来,对他和HashSet都继承了abstractset没问题,但是TreeSet另外实现了一个navigableset接口,这个接口又继承了sortedset接口,而sortedset接口才继承我们的set接口,而HashSet是直接实现set接口类的,而TreeSet实现类最大的特点就是有序性,这我们就不得不提到sortedset接口的原因了,这个接口继承了set接口但是另外他自己又扩展了排序的方法,而这个接口类的子接口类navigableset类在sortedset接口类上实现了进一步扩展,实现了很多关于比较和升倒序的一些方法,所以也就有了TreeSet实现类元素不重复的保证有自然排序和比较器排序。 2 ———————————————— 3 版权声明:本文为CSDN博主「waves6248」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。 4 原文链接:https://blog.csdn.net/waves6248/article/details/87361451
1 集合map接口下的linkedhashmap,首先他继承了实现类hashmap,实现了map接口类,而hashmap实现类又继承了abstractmap抽象类,实现了标记类cloneable和serializable,map接口特点键值对,键唯一,值不唯一,hashmap特点底层实现为“数组+链表+红黑树”当链表的长度大于8时,转化为红黑树存储,这里简单说一下是头节点是索引位置的节点,链表的头节点,跟节点是最顶级节点,也就是没有父节点的节点,根节点不一定是索引位置的头节点,但是这并不影响红黑树结构和链表结构,希望这里注意,然后是hashmap在遍历的时候其实并不能按照插入的顺序遍历而是随机的,而是他的子类linkedhashmap实现类,扩展了记录插入位置,所以他是有序的,但是同时他和hashmap都是线程不安全的。 2 ———————————————— 3 版权声明:本文为CSDN博主「waves6248」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。 4 原文链接:https://blog.csdn.net/waves6248/article/details/87361451
1 TreeMap实现了serializable接口,cloneable接口和NavigableMap接口,还有就是继承了AbstractMap抽象类,这些就说明TreeMap能够分别说明实现序列化,能够被克隆复制,还有就是能够实现有序的排序和比较大小等等,如果还有什么木有反应过来为什么可以看看我之前写的其他集合,这些还是比较明确的,同时NavigableMap接口继承了SortedMap接口,这个接口才是保证TreeMap是有序的,主要靠这个接口提供,还有这里同时也对应了前面讲的NavigableSet和SortedSet都是依赖NavigableMap和SortedMap。 2 ———————————————— 3 版权声明:本文为CSDN博主「waves6248」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。 4 原文链接:https://blog.csdn.net/waves6248/article/details/87361451
1 首先讲Hashtable它同样是实现了serializable,cloneable,map接口和继承了dictionary抽象类但是这个抽象和map很像而且现在比较过时所以我就不讲了,其他的图一已经将过,然后这个实现类最大的特点就是用哈希表存数据就是可以将关键值码存到表中一个位置,以加快查找速度,weakHashmap两个特点一个是弱引用,二是适用于需要缓存的场景,identifyhashmap最大的特点就是key可以重复,但是不能是同一个对象。 2 ———————————————— 3 版权声明:本文为CSDN博主「waves6248」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。 4 原文链接:https://blog.csdn.net/waves6248/article/details/87361451
31. collection和collections的区别;
1 Collection是JDK中集合层次结构中的最根本的接口。定义了集合类的基本方法。源码中的解释: 2 3 * The root interface in the <i>collection hierarchy</i>. A collection 4 * represents a group of objects, known as its <i>elements</i>. Some 5 * collections allow duplicate elements and others do not. Some are ordered 6 * and others unordered. The JDK does not provide any <i>direct</i> 7 * implementations of this interface: it provides implementations of more 8 * specific subinterfaces like <tt>Set</tt> and <tt>List</tt>. This interface 9 * is typically used to pass collections around and manipulate them where 10 * maximum generality is desired. 11 Collections是一个包装类。它包含有各种有关集合操作的静态多态方法,不能实例化,像一个Collection集合框架中的工具类。 12 13 * This class consists exclusively of static methods that operate on or return 14 * collections. It contains polymorphic algorithms that operate on 15 * collections, "wrappers", which return a new collection backed by a 16 * specified collection, and a few other odds and ends 17 ———————————————— 18 版权声明:本文为CSDN博主「ConstXiong」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。 19 原文链接:https://blog.csdn.net/meism5/article/details/89716912
32. 线程的概念?创建线程的方法?线程的生命周期?
1 1. 线程生命周期 2 3 线程生命周期图 4 5 6 新建状态(New) 7 当线程对象创建后,即进入新建状态,如:Thread t = new MyThread(); 8 9 就绪状态(Runnable) 10 当调用线程对象的start()方法时,线程即进入就绪状态。处于就绪状态的线程只是说明此线程已经做好准备,随时等待CPU调度执行,并不是说执行了start()方法就立即执行。 11 12 运行状态(Running) 13 当CPU开始调度处于就绪状态的线程时,此时线程才得以真正执行,即进入到运行状态。 14 15 阻塞状态(Blocked) 16 处于运行状态中的线程由于某种原因,暂时放弃对CPU的使用权,停止执行,此时进入阻塞状态,直到其进入到就绪状态,才有机会再次被CPU调用以进入到运行状态。 17 18 死亡状态 19 线程执行完毕或者是异常退出,该线程结束生命周期。 20 21 阻塞状态分类 22 23 等待阻塞:运行状态中的线程执行wait()方法,使本线程进入到等待阻塞状态; 24 同步阻塞:线程在获取synchronized同步锁失败(因为锁被其它线程占用),它会进入到同步阻塞状态; 25 其他阻塞:通过调用线程的sleep()或join()或发出I/O请求时,线程会进入到阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。 26 2. 线程状态控制 27 28 线程休眠-sleep() 29 sleep()会让当前的线程暂停一段时间,并进入阻塞状态,调用sleep并不会释放锁。 30 注意点: 31 32 sleep()是静态方法,故不要用线程实例对象调用它,它睡眠的始终是当前正在运行的线程,而不是调用它的线程对象。 33 线程实际休眠时间会大于设定的时间。 34 sleep()方法声明抛出InterruptedException,所以调用sleep()需要捕获异常。 35 线程让步-yield() 36 调用yield()方法之后,从运行状态转换到就绪状态,CPU从就绪状态队列中只会选择与该线程优先级相同或者是优先级更高的线程去执行。 37 38 yield()方法不需要抛出异常。 39 40 线程合并-join() 41 线程合并就是将几个并发线程合并为一个单一线程执行,应用场景就是当一个线程的执行必须是要等到其他线程执行完毕之后才能执行。 42 43 线程优先级设置-priority 44 Thread类提供setPriority(int newPriority)和getPriority()方法设置和返回优先级。 45 46 守护线程-Daemon 47 守护线程是为其他非守护线程提供服务的,比如JVM中的垃圾回收线程就是守护线程。当所有的前台线程都进入死亡状态时,守护线程会自动死亡。 48 49 调用Thead实例的setDaemon(true)方法可以将指定的线程设置为守护线程。 50 51 3. 线程创建方式 52 53 1.通过继承Thread类来创建并启动多线程的方式。 54 Java所有的线程对象都必须是Thread类或其子类的实例。每个线程的作用是完成一定的任务,实际上就是执行一段程序流即一段顺序执行的代码。Java使用线程执行体来代表这段程序流。Java中通过继承Thread类来创建并启动多线程的步骤如下: 55 56 定义Thread类的子类,并重写该类的run()方法,run()方法即称为线程执行体。 57 创建Thread子类的实例。 58 调用线程对象的start()方法来启动该线程。 59 继承Thread类创建线程示例 60 61 public class MyThreadTest extends Thread { 62 private int i; 63 64 @Override 65 public void run(){ 66 for (; i < 100; i++) { 67 System.out.println(this.getName() + " " + i); 68 } 69 } 70 71 public static void main(String[] args) { 72 for (int i = 0; i < 100; i++) { 73 // 调用Thread的currentThread方法获取当前线程 74 System.out.println(Thread.currentThread().getName() + " " + i); 75 if (i == 20) { 76 // 创建、并启动第一条线程 77 new MyThreadTest().start(); 78 // 创建、并启动第二条线程 79 new MyThreadTest().start(); 80 } 81 } 82 } 83 } 84 1 85 2 86 3 87 4 88 5 89 6 90 7 91 8 92 9 93 10 94 11 95 12 96 13 97 14 98 15 99 16 100 17 101 18 102 19 103 20 104 21 105 22 106 23 107 2.通过实现Runnable接口来创建并启动线程的方式。 108 实现Runnable接口创建线程步骤如下: 109 110 定义Runnable接口的实现类,并重写该接口的run()方法。 111 创建Runnable实现类的实例,并以此实例作为Thread的target来创建Thread对象,该Thread对象才是真正的线程对象。 112 调用线程对象的start()方法来启动线程。 113 需要注意的是:Runnable对象仅仅作为Thread对象的target,Runnable实现类里包含的run()方法仅作为线程执行体。而实际的线程对象依然是Thread实例,只是该Thread线程负责执行其target的run()方法。 114 115 实现Runnable接口创建线程示例 116 117 public class MyRunnableTest implements Runnable { 118 private int i; 119 120 void print() { 121 System.out.println(Thread.currentThread().getName() + " " + i); 122 } 123 124 @Override 125 public void run() { 126 for (; i < 100; i++) { 127 print(); 128 } 129 } 130 131 public static void main(String[] args) { 132 for (int i = 0; i < 100; i++) { 133 System.out.println(Thread.currentThread().getName() + " " + i); 134 if (i == 20) { 135 MyRunnableTest st = new MyRunnableTest(); 136 // 通过new Thread(target, name)方法创建新线程 137 // new Thread(st).start();亦可 138 new Thread(st, "新线程-1").start(); 139 new Thread(st, "新线程-2").start(); 140 } 141 } 142 } 143 } 171 部分运行结果: 172 173 174 从该运行结果中我们可以看出,控制台上输出的内容是乱序的,而且每次结果不尽相同。这是因为: 175 176 在这种方式下,程序所创建的Runnable对象只是线程的target,而多个线程共享同一个target,所以多个线程共享同一个线程类即线程的target类的实例属性。 177 print()方法并不是线程安全的。 178 解决方案:对print()方法添加synchronized关键字保证线程安全。 179 180 synchronized void print() { 181 System.out.println(Thread.currentThread().getName() + " " + i); 182 } 183 1 184 2 185 3 186 3.通过实现Callable接口来创建并启动线程的方式。 187 从Java 5开始,Java提供了Callable接口,Callable接口提供了一个call()方法可以作为线程执行体,但call()方法比run()方法功能更强大。 188 189 call()方法可以有返回值; 190 call()方法可以声明抛出异常。 191 Java 5提供了Future接口来代表Callable接口call()方法的返回值,并为Future接口提供了一个FutureTask实现类,该实现类实现了Future接口和Runnable接口可以作为Thread类的target。 192 注意:Callable接口有泛型限制,Callable接口里的泛型形参类型与call()方法返回值类型相同。 193 194 创建并启动有返回值的线程的步骤如下: 195 196 创建Callable接口的实现类,并实现call()方法,该call()方法将作为线程执行体,且该call()方法有返回值。 197 创建Callable实现类的实例,使用FutureTask类来包装Callable对象,该FutureTask对象封装了call()方法的返回值。 198 使用FutureTask对象作为Thread对象的target创建并启动新线程。 199 调用FutureTask对象的get()方法来获得子线程执行结束后的返回值。 200 注意:get()方法用来获取执行结果,这个方法会产生阻塞,会一直等到任务执行完毕才返回。另外FutureTask还提供了get(long timeout, TimeUnit unit)方法,如果在指定时间内,还没获取到结果,就直接返回null。 201 202 实现Callable接口创建线程示例 203 204 public class MyCallableTest implements Callable<Integer> { 205 206 @Override 207 public Integer call() throws Exception { 208 int i = 0; 209 for (; i < 100; i++) { 210 System.out.println(Thread.currentThread().getName() + " " + i); 211 } 212 return i; 213 } 214 215 public static void main(String[] args) { 216 // 创建Callable对象 217 MyCallableTest myCallableTest = new MyCallableTest(); 218 // 使用FutureTask来包装Callable对象 219 FutureTask<Integer> task = new FutureTask<Integer>(myCallableTest); 220 for (int i = 0; i < 100; i++) { 221 System.out.println(Thread.currentThread().getName() + " " + i); 222 if (i == 20) { 223 // 实质还是以Callable对象来创建、并启动线程 224 new Thread(task, "callable").start(); 225 } 226 } 227 try { 228 System.out.println("callable返回值:" + task.get()); 229 } catch (Exception e) { 230 e.printStackTrace(); 231 } 232 } 233 } 234 264 总结:三种方式创建线程,继承Thread类,实现Runnable接口和实现Callable接口。实现Runnable接口和实现Callable接口的方式多个线程可以共享一个target对象,比较适用多个相同线程处理同一份资源的情况。 265 ———————————————— 266 版权声明:本文为CSDN博主「编码小农」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。 267 原文链接:https://blog.csdn.net/weixin_36759405/article/details/82843399
33. Thread 和Runable的区别?
1 Java中创建线程有两种方式: 2 3 通过继承Thread类 4 实现Runnable接口 5 6 我们都知道使用多线程编程,那么为什么使用他呢?他有什么优势? 7 8 当使用单线程编程时,可能遇到进程阻塞现象(例如:I/O流读取错误,堆栈溢出等等,我们不可控),这时整个进程就会挂掉,直到外部条件发生变化。而使用多线程就不会出现这样的问题,我们会将单个进程拆分成很多独立的、拥有自己功能的一个个任务,这样一个任务阻塞,其他任务还会继续运行。 9 10 那么我们来看看Thread类: 11 12 public static void main(String[] args) { 13 //创建多个线程,并启动。 14 new ActualThread().start(); 15 new ActualThread().start(); 16 new ActualThread().start(); 17 new ActualThread().start(); 18 } 19 public class ActualThread extends Thread{ 20 21 private int count = 10; 22 @Override 23 public void run(){ 24 while(count>0){ 25 System.out.println(Thread.currentThread().getName() + "-------" + count--); 26 try { 27 //休眠4000毫秒 28 sleep(4000); 29 } catch (InterruptedException e) { 30 // TODO Auto-generated catch block 31 e.printStackTrace(); 32 } 33 } 34 } 35 } 36 1 37 2 38 3 39 4 40 5 41 6 42 7 43 8 44 9 45 10 46 11 47 12 48 13 49 14 50 15 51 16 52 17 53 18 54 19 55 20 56 21 57 22 58 23 59 24 60 结果: 61 62 Thread-0——-5 63 Thread-2——-5 64 Thread-1——-5 65 Thread-3——-5 66 Thread-2——-4 67 Thread-3——-4 68 Thread-1——-4 69 Thread-0——-4 70 Thread-2——-3 71 Thread-1——-3 72 Thread-3——-3 73 Thread-0——-3 74 Thread-2——-2 75 Thread-3——-2 76 Thread-1——-2 77 Thread-0——-2 78 Thread-1——-1 79 Thread-2——-1 80 Thread-3——-1 81 Thread-0——-1 82 83 从上面的结果我们会得出一个有趣的结论,windows任务调度是:基于优先级的时间片轮转法调度线程。 84 每一次New ActualThread()都会创建一个新的线程实例。 85 这4个线程彼此之间互不干扰,各自占有各自的资源,并不是统一完成任务。 86 由此可以得出:Thread类无法达到资源共享的目的。 87 88 我们再来看下通过实现Runnable接口生成的线程。 89 90 public class ThreadDemo { 91 92 public static void main(String[] args) { 93 RunnableThread runnableThread = new RunnableThread(); 94 //new Thread(Runnable target)创建一个新的Thread对象 95 new Thread(runnableThread).start(); 96 new Thread(runnableThread).start(); 97 new Thread(runnableThread).start(); 98 new Thread(runnableThread).start(); 99 } 100 101 public class RunnableThread implements Runnable{ 102 103 private int count = 10; 104 @Override 105 public void run() { 106 while(count>0){ 107 System.out.println(Thread.currentThread().getName() + "-------" + count--); 108 } 109 } 110 } 111 1 112 2 113 3 114 4 115 5 116 6 117 7 118 8 119 9 120 10 121 11 122 12 123 13 124 14 125 15 126 16 127 17 128 18 129 19 130 20 131 21 132 结果: 133 134 Thread-0——-10 135 Thread-3——-7 136 Thread-3——-5 137 Thread-2——-8 138 Thread-1——-9 139 Thread-2——-3 140 Thread-3——-4 141 Thread-0——-6 142 Thread-2——-1 143 Thread-1——-2 144 145 我们发现这4个线程之间彼此协作完成任务,共享资源。 146 147 由此我们得出结论: 148 Runnable适合拥有相同程序代码的线程去处理统一资源的情况,把虚拟的CPU(线程)、程序和数据有效的分离,较好体现面向编程思想。 149 Runnable可以避免由于单继承机制带来的局限性。可以在继承其他类的同时,是能实现多线程功能。 150 Runnable能够增强程序的健壮性,代码能够被多个线程共享。 151 为什么会出现这样的现象呢? 152 我们来看JDK的源码: 153 154 @Override 155 public void run() { 156 if (target != null) { 157 target.run(); 158 } 159 } 160 1 161 2 162 3 163 4 164 5 165 6 166 上面这段代码是Thread类中的run()方法,重写了Runnable接口的run(),这个方法定义如果当前线程有实现了Runnable接口的实例的引用(target),就调用target对象的run()方法,否则就会调用自己(Thread对象)的run()方法。如果创建多个线程,将Runnable实例作为参数创建的线程实际上处理的就是:Runnable实例的资源(注意,这里多个线程中只有一个Runnable实例)也即是说,count是Runnable实例的。这也就解释了为什么实现了Runnable接口的线程会处理同一资源。而通过Thread类自己创建的count是独属于每个线程自己独属的资源。这些就解释了Thread和Runnable接口会有这样的差别。 167 提示:这里使用了静态代理模式。有兴趣的同学可以去了解一下。 168 169 还有就是Runnable的理解问题 170 通过上面的程序(new Thread(runnableThread).start();)我们发现,实则,Runnable的实例类并不是线程,它是作为一个参数传递进Thread类中,Thread才是真正的线程,而Rnnnable只是任务,任务和线程是分开的,任务放在线程里面才会执行。如果将Runnable的命名改为Task就好理解多了,这也更容易解释为什么有Runnable实例的线程会相互协作处理统一资源。就是因为他是任务而不是线程。 171 总结: 172 实现Runnable接口的实例是线程任务的定义者。 173 继承Thread类的实例是线程的创建者 174 ———————————————— 175 版权声明:本文为CSDN博主「人生哪有不迷茫」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。 176 原文链接:https://blog.csdn.net/Done_FollowMyHeart/article/details/81536974
34. 编程:请使用线程循环打印出A B A B A B。。。。
1 package com.baidu.controller; 2 3 4 public class czg { 5 6 /** 7 * @param args 8 */ 9 10 11 public static void main(String[] args) { 12 // TODO Auto-generated method stub 13 14 PrintTask printTask=new PrintTask(); 15 Thread thread1=new Thread(printTask,"A"); 16 Thread thread2=new Thread(printTask,"B"); 17 Thread thread3=new Thread(printTask,"c"); 18 thread1.start(); 19 thread2.start(); 20 thread3.start(); 21 22 23 } 24 25 26 } 27 28 class PrintTask implements Runnable { 29 //用来标识当前应该是a还是b或者c 30 private int count = 0; 31 32 // private ReentrantLock lock=new ReentrantLock(); 33 @Override 34 public void run() { 35 // TODO Auto-generated method stub 36 String nameString = Thread.currentThread().getName(); 37 // lock.lock(); 38 //this的含义是什么 39 while (count < 30) { 40 synchronized (this) { 41 if (count % 3 == 0) { 42 //a 43 if (nameString.equalsIgnoreCase("A")) { 44 System.out.print("A"); 45 count++; 46 this.notifyAll(); 47 } else { 48 try { 49 this.wait(); 50 } catch (InterruptedException e) { 51 // TODO Auto-generated catch block 52 e.printStackTrace(); 53 } 54 } 55 } 56 if (count % 3 == 1) { 57 //b 58 if (nameString.equalsIgnoreCase("B")) { 59 System.out.print("B"); 60 count++; 61 this.notifyAll(); 62 } else { 63 try { 64 this.wait(); 65 } catch (InterruptedException e) { 66 // TODO Auto-generated catch block 67 e.printStackTrace(); 68 } 69 } 70 } 71 if (count % 3 == 2) { 72 if (nameString.equalsIgnoreCase("C")) { 73 System.out.print("C"); 74 count++; 75 this.notifyAll(); 76 } else { 77 try { 78 this.wait(); 79 } catch (InterruptedException e) { 80 // TODO Auto-generated catch block 81 e.printStackTrace(); 82 } 83 } 84 } 85 } 86 } 87 88 89 // lock.unlock(); 90 91 92 } 93 } 94
原文地址:https://www.cnblogs.com/czg-0705/p/11898584.html