大家好,又见面了,我是你们的朋友全栈君。
***************** java基础 *****************
一、java 中的局部变量、实例变量和类变量
二、java中的基本类型和引用类型
三、java中的位操作符
四、关于 java 的方法
1、方法的重载和重写(方法签名:方法名和参数列表)
2、方法的可变参(int … args)
(1)基本特点
底层就是用数组来实现的;
在方法内部可变参可以直接当成数组进行操作;
方法调用的时候,可以传递多个参数,也可以传递数组,还可以不传或者传递一个 null;
一个参数列表只能有一个可变参,而且只能写在最后;
(2)可变参对方法重载的影响
参数是数组的方法和可变参方法不能共存;
空参方法和可变参方法可以共存,不传递参数的时候默认调用空参方法(子类没有就找父类),实在没有空参,才会调用可变参方法;
(String…strs)、(String str,String…strs) 、(String str)、(String str,String str2)这样的参数列表是可以共存的,只是为了区分方法参数传递的时候比较麻烦;
3、关于构造方法(用来初始化对象)
是一个特殊的方法,方法名和类名相同,无返回值声明(实际上会返回对象),可以空参也可以含参;
在不写构造器的情况下,JVM会自动在一个类中注入一个空参的构造器,如果写了构造器(不管有参还是无参),则不会自动生成;
许多框架在对类进行实例化的时候会调用空参构造器,所以在构建类的时候最好明确提供一个空参的构造器以防止出错;
构造器一般用 public 修饰,少数情况会将构造器私有,来限制类对象的创建(比如单例设计的时候);
4、关于类的初始化顺序
五、java枚举(enum)
六、java异常处理
1、错误和异常
(1)错误 error
运行时发生错误,编译器无法检查
从Error中恢复是不可能的
Error主要是由运行应用程序的环境引起的
示例:java.lang.StackOverflowError,java.lang.OutOfMemoryError
(2)异常 exception
异常包括检查异常(对编译器已知)和未检查异常(运行时发生,对编译器未知)
可以通过try-catch块处理异常来恢复异常
异常主要是由应用程序本身引起的
检查异常:SQLException,IOException 运行时异常:ArrayIndexOutOfBoundException,ClassCastException,NullPointerException
(3)个人理解:出现异常和错误都意味着我们的程序出现了问题,异常是我们能够截获和处理的问题,另一些问题比较严重,是我们不应截获和无法处理的,这些就是错误
2、检查异常和运行时异常
二者都是在运行的时候发生;
检查异常是编译器能够预知的异常,代码中可能出现检查异常编译器会强制我们进行处理;
运行时异常是无法预知的,因为一些程序的逻辑问题(数组下标越界等)可能在运行时抛出;
运行时异常不具有代码侵入性,抛出运行时异常无需在方法声明的时候写 throws 语句;
检查异常如果不用 try–catch 进行处理,从异常发生方法一直到顶层的调用方法都需要写 throws 语句;
3、try–catch–finally 语句块
如果发生异常,try 的语句块中,发生异常的语句后面的语句会被跳过;
try-catch-finally 后面还有语句,这些语句无论是否发生异常都会执行(前提是前面没有 return);
finally 中的语句执行的时机是在 return 之前,finally中最好不要有 return ,因为可能会覆盖 try–catch 中的 return;
4、为什么需要自定义异常
统一了对外异常展示的方式,可以隐藏底层的异常,这样更安全,异常信息也更加的直观;
系统中有些错误是符合Java语法的,但不符合我们项目的业务逻辑,需要使用自定义异常来进行处理;
6、java中的异常链
异常链是一种面向对象编程技术,指将捕获的异常包装进一个新的异常中并重新抛出的异常处理方式,原异常被保存为新异常的一个属性(比如cause);
把捕获的异常包装成新的异常,经过层层的包装,就像链式反应一样,一个导致(cause)另一个,这样最顶层抛出的异常中也能获取到底层的异常信息(getCause方法);
异常链的意义是一个方法应该抛出定义在相同的抽象层次上的异常,同时也不应丢弃更低层次的异常信息;
异常需要封装和传递,我们在进行系统开发的时候,不要“吞噬”异常,也不要“赤裸裸”的抛出异常,封装后在抛出,通过异常链传递,可以使系统更健壮友好;
java进阶*
一、注解(@interface)
1、注解的本质:
java语言中有四种类型(TYPE),即类(class)、枚举(enum)、接口(interface)和注解(@interface);
注解的本质就是一个继承了 Annotation 接口的特殊的接口,可以用来为类、方法、成员变量等关联任何信息;
2、注解和元数据
元数据指用来描述数据的数据,具体指描述代码间关系或者代码与其它资源(例如数据库表)之间内在联系的数据;
各种框架的配置文件(通常是xml文件)就是用来描述元数据的,其弊端在于与被描述的文件分离,不利于一致性维护;
注解也是用来描述元数据的一种形式,这种方式使得元数据和被描述对象结合紧密,有利于一致性维护,缺点就是耦合度高一些;
3、注解分类
(1)JDK内置系统注解
@Override:用于修饰此方法覆盖了父类的方法,不符合重写的规则会报错;
@Deprecated:用于修饰已经过时的方法,此注解修饰方法不建议使用;
@SuppressWarnnings:用于通知 java 编译器禁止特定的编译警告,有很多可选的项(all、unused);
(2)元注解:就是描述其他注解的注解
@Target:描述注解的作用对象(ElementType.FIELD)
@Retention:描述注解的生命周期(RetentionPolicy.RUNTIME)
@Documented:支持 javadoc 等工具文档化;
@Inherited:注解可以被子类继承;
(3)自定义注解:注解的参数用方法描述(方法名为参数名,返回值类型是参数类型,default指定默认值)
4、通过反射来使用注解
反射的基本过程:获得 class 文件对象(字节码对象)— 字节码对象方法获取 Field 和 Method 等 — 通过这些对象的 api 进行相关操作;
反射能获取注解的前提就是注解的生命周期必须是 runtime,反射得到的 Field 和 Method 等实际是 AnnotatedElement 接口的实现类,此接口提供api操作注解;
常用的操作注解的 API 如下:
二、java反射和动态代理
1、反射:本质就是通过字节码对象对类进行解构,获得类的属性和方法,从而对该类进行一些特殊的操作
反射的核心就是获取 class 文件对象:Class.forName(“全限定名”) —– java.io.PrintStream.class—–“foo”.getClass();
通过反射创建实例:可以通过 class 或者 constructor 的 newinstance 方法创建对象;
class 文件对象有相应的 api 可以获取类的 Field、Method 和 Constructor;甚至是可以访问类的私有成员;
2、动态代理
(1)静态代理–动态代理
代理模式的实现:要么是通过继承使得代理对象和被访问者具有相同的方法,要么就是通过实现接口达到这个目的;
静态代理:代理的类一直存在,会导致系统臃肿和难以维护;
动态代理:代理类不是一直存在的,访问的时候动态创建,结束访问后自动销毁,可以大大的节约资源;
(2)动态代理核心 API
核心的类:InvocationHandler 和 Proxy;
核心方法:proxy 类的 newProxyInstance 方法和 InvocationHandler 的 invoke(classloader,interfaces,handler);
三、java泛型
1、泛型本质:java 类型的参数化,增强 java 语言的动态性,使得可以编写出适用于各种类型的通用代码
2、泛型应用:泛型接口、泛型类、泛型方法(一般情况用泛型方法,不要轻易使用泛型类,有利于明确泛型化的范围)
3、泛型擦除:泛型只存在于编译期,编译好的 class 文件反编译之后是看不到泛型的(伪泛型,目的是为了兼容以前没有泛型的版本)
4、擦除补偿
(1)擦除带来的问题:以下的操作都无法通过编译,还有在泛型类和泛型方法的内部,泛型就等同于一个 object,不能调用某个类特有的方法
if(obj instanceof T);
T t = new T();
T[] ts = new T[10];
(2)解决方案:
instanceof 方法可以用 class对象的 isInstance 方法替代;
实例的创建也可以通过 class 对象的 newInstance 来创建;没有无参构造的还可以通过反射获取构造器,通过构造器的 newInstance 方法创建;还可以使用工厂来创建;
泛型数组的数组的创建可以直接用 ArrayList 来代替(底层就是用数组实现的);非要用数组的话可以通过反射包里的 Array 类的 newInstance 方法来创建;
5、泛型边界
Generator 通过这样的定义可以使得泛型类内部可以调用 Apple 类的特有方法,但实际上这靠 java 的多态就能实现不需要使用泛型;
上述的定义中只能使用 extends 而不能使用 super ,因为向上的转型是自动的,而向下的转型需要强制进行;
6、通配符和上下界:上界 <? extends Fruit> 下界 <? super Apple>
(1)PECS法则总结(Producer Extends,Consumer Super)
如果要从集合中读取类型E的数据,并且不能写入,可以使用 ? extends 通配符;
如果要从集合中写入类型E的数据,并且不需要读取,可以使用 ? super 通配符;
如果既要存又要取,那么就不要使用任何通配符;
(2)原理:List<? extends Fruit>
意思是具有 Fruit 子类类型,但是无法确定到底是 Fruit 的哪个子类,所以往里面 add 元素会报错(除了null);
get方法正常使用因为无论什么子类都是可以向上转型为 Fruit,所以直接用 Fruit 来接受即可;
contains 和 indexOf 方法能正常工作因为他们的参数是 Object 类型和泛型无关,所以能够使用;
(3)原理: List<? super Apple>
意思是具有 Apple 父类的列表,无法确定具体是哪一个父类所以无法向其中 add apple 的父类类型;
可以向其中 add Apple 的子类是因为不管你 add 哪个子类反正都会自动向上转型为 apple 的父类类型;
不建议使用 get 方法,但非要用的话只能使用一个 Object 来接受;
7、参考资料:https://blog.csdn.net/jeffleo/article/details/52250948
四、输入输出流
1、传统的IO流(具体的总结参考博客)
(1)字节流的乱码问题:通过 new String()转换一下编码即可,保证读和写的编码一致;
(2)字符流的乱码问题:需要通过 InputStreamReader 将字节流转成字符流的时候设置合适的编码;
2、java NIO(示例代码参考)
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/156679.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...