本文是我花了三周工夫整理出来的,心愿对Java初学者有帮忙~
Java概述
Java的特点
Java是一门面向对象的编程语言。面向对象和面向过程是一种软件开发思维。
面向过程就是剖析出解决问题所须要的步骤,而后用函数按这些步骤实现,应用的时候顺次调用就能够了。面向对象是把形成问题事务分解成各个对象,别离设计这些对象,而后将他们组装成有残缺性能的零碎。面向过程只用函数实现,面向对象是用类实现各个功能模块。
例如五子棋,面向过程的设计思路就是首先剖析问题的步骤:
1、开始游戏,2、黑子先走,3、绘制画面,4、判断输赢,5、轮到白子,6、绘制画面,7、判断输赢,8、返回步骤2,9、输入最初后果。
把下面每个步骤用别离的函数来实现,问题就解决了。- 而面向对象的设计则是从另外的思路来解决问题。整个五子棋能够分为:
1、黑白单方
2、棋盘零碎,负责绘制画面
3、规定零碎,负责断定诸如犯规、输赢等。
黑白单方负责承受用户的输出,并告知棋盘零碎棋子布局发生变化,棋盘零碎接管到了棋子的变动的信息就负责在屏幕下面显示出这种变动,同时利用规定零碎来对棋局进行断定。
Java具备平台独立性和移植性。
- Java有一句口号:Write once, run anywhere,一次编写、到处运行。这也是Java的魅力所在。而实现这种个性的正是Java虚拟机JVM。已编译的Java程序能够在任何带有JVM的平台上运行。你能够在windows平台编写代码,而后拿到linux上运行。只有你在编写完代码后,将代码编译成.class文件,再把class文件打成Java包,这个jar包就能够在不同的平台上运行了。
Java具备稳健性。
- Java是一个强类型语言,它容许扩大编译时查看潜在类型不匹配问题的性能。Java要求显式的办法申明,它不反对C格调的隐式申明。这些严格的要求保障编译程序能捕获调用谬误,这就导致更牢靠的程序。
- 异样解决是Java中使得程序更持重的另一个特色。异样是某种相似于谬误的异样条件呈现的信号。应用try/catch/finally语句,程序员能够找到出错的解决代码,这就简化了出错解决和复原的工作。
JKD和JRE
JDK和JRE是Java开发和运行工具,其中JDK蕴含了JRE,而JRE是能够独立装置的。
JDK
Java Development Kit,JAVA语言的软件工具开发包,是整个JAVA开发的外围,它蕴含了JAVA的运行(JVM+JAVA类库)环境和JAVA工具。
JRE
JRE(Java Runtime Environment,Java运行环境):蕴含JVM规范实现及Java外围类库。JRE是Java运行环境,并不是一个开发环境,所以没有蕴含任何开发工具(如编译器和调试器)。
JRE是运行基于Java语言编写的程序所不可短少的运行环境。也是通过它,Java的开发者才得以将本人开发的程序公布到用户手中,让用户应用。
Java根底语法
根本数据类型
- byte,8bit
- char,16bit
- short,16bit
- int,32bit
- float,32bit
- long,64bit
- double,64bit
- boolean,只有两个值:true、false,能够使⽤用 1 bit 来存储,然而具体⼤小没有明确规定。
包装类型
根本类型都有对应的包装类型,根本类型与其对应的包装类型之间的赋值通过主动装箱与拆箱实现。
Integer x = 1; // 装箱 调⽤ Integer.valueOf(1)int y = x; // 拆箱 调⽤了 X.intValue()
包装类缓存
应用Integer.valueOf(i)生成Integer,如果 -128 <= i <= 127,则间接从cache取对象返回,不会创立新的对象,防止频繁创立包装类对象。
public static Integer valueOf(int i) { if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); }
String
String是final类,不可被继承。
String拼接
字符串拼接能够应用String用+做拼接,也能够应用StringBuilder和StringBuffer实现,三种形式比照:
- 底层都是char数组实现的
- 字符串拼接性能:StringBuilder > StringBuffer > String
- String 是字符串常量,一旦创立之后该对象是不可更改的,用+对String做拼接操作,实际上是先通过建设StringBuilder,而后调用append()做拼接操作,所以在大量字符串拼接的时候,会频繁创立StringBuilder,性能较差。
- StringBuilder和StringBuffer的对象是字符串变量,对变量进行操作就是间接对该对象进行批改(批改char[]数组),所以速度要比String快很多。
- 在线程平安上,StringBuilder是线程不平安的,而StringBuffer是线程平安的,StringBuffer中很多办法带有synchronized关键字,能够保障线程平安。
关键字
static
static能够用来润饰类的成员办法、类的成员变量。
动态变量
static变量也称作动态变量,动态变量和非动态变量的区别是:动态变量被所有的对象所共享,在内存中只有一个正本,它当且仅当在类首次加载时会被初始化。而非动态变量是对象所领有的,在创建对象的时候被初始化,存在多个正本,各个对象领有的正本互不影响。
以下例子,age为非动态变量,则p1打印后果是:Name:zhangsan, Age:10
;若age应用static润饰,则p1打印后果是:Name:zhangsan, Age:12
,因为static变量在内存只有一个正本。
public class Person { String name; int age; public String toString() { return "Name:" + name + ", Age:" + age; } public static void main(String[] args) { Person p1 = new Person(); p1.name = "zhangsan"; p1.age = 10; Person p2 = new Person(); p2.name = "lisi"; p2.age = 12; System.out.println(p1); System.out.println(p2); } /**Output * Name:zhangsan, Age:10 * Name:lisi, Age:12 *///~}
静态方法
static办法个别称作静态方法。静态方法不依赖于任何对象就能够进行拜访,通过类名即可调用静态方法。
public class Utils { public static void print(String s) { System.out.println("hello world: " + s); } public static void main(String[] args) { Utils.print("程序员大彬"); }}
动态代码块
动态代码块只会在类加载的时候执行一次。以下例子,startDate和endDate在类加载的时候进行赋值。
class Person { private Date birthDate; private static Date startDate, endDate; static{ startDate = Date.valueOf("2008"); endDate = Date.valueOf("2021"); } public Person(Date birthDate) { this.birthDate = birthDate; }}
动态外部类
在静态方法里,应用⾮动态外部类依赖于外部类的实例,也就是说须要先创立外部类实例,能力用这个实例去创立非动态外部类。⽽动态外部类不须要。
public class OuterClass { class InnerClass { } static class StaticInnerClass { } public static void main(String[] args) { // 在静态方法里,不能间接应用OuterClass.this去创立InnerClass的实例 // 须要先创立OuterClass的实例o,而后通过o创立InnerClass的实例 // InnerClass innerClass = new InnerClass(); OuterClass outerClass = new OuterClass(); InnerClass innerClass = outerClass.new InnerClass(); StaticInnerClass staticInnerClass = new StaticInnerClass(); outerClass.test(); } public void nonStaticMethod() { InnerClass innerClass = new InnerClass(); System.out.println("nonStaticMethod..."); }}
final
- 根本数据类型用final润饰,则不能批改,是常量;对象援用用final润饰,则援用只能指向该对象,不能指向别的对象,然而对象自身能够批改。
- final润饰的办法不能被子类重写
- final润饰的类不能被继承。
object罕用办法
Java面试常常会呈现的一道题目,Object的罕用办法。上面给大家整顿一下。
object罕用办法有:toString()、equals()、hashCode()、clone()等。
toString
默认输入对象地址。
public class Person { private int age; private String name; public Person(int age, String name) { this.age = age; this.name = name; } public static void main(String[] args) { System.out.println(new Person(18, "程序员大彬").toString()); } //output //me.tyson.java.core.Person@4554617c}
能够重写toString办法,依照重写逻辑输入对象值。
public class Person { private int age; private String name; public Person(int age, String name) { this.age = age; this.name = name; } @Override public String toString() { return name + ":" + age; } public static void main(String[] args) { System.out.println(new Person(18, "程序员大彬").toString()); } //output //程序员大彬:18}
equals
默认比拟两个援用变量是否指向同一个对象(内存地址)。
public class Person { private int age; private String name; public Person(int age, String name) { this.age = age; this.name = name; } public static void main(String[] args) { String name = "程序员大彬"; Person p1 = new Person(18, name); Person p2 = new Person(18, name); System.out.println(p1.equals(p2)); } //output //false}
能够重写equals办法,依照age和name是否相等来判断:
public class Person { private int age; private String name; public Person(int age, String name) { this.age = age; this.name = name; } @Override public boolean equals(Object o) { if (o instanceof Person) { Person p = (Person) o; return age == p.age && name.equals(p.name); } return false; } public static void main(String[] args) { String name = "程序员大彬"; Person p1 = new Person(18, name); Person p2 = new Person(18, name); System.out.println(p1.equals(p2)); } //output //true}
hashCode
将与对象相干的信息映射成一个哈希值,默认的实现hashCode值是依据内存地址换算进去。
public class Cat { public static void main(String[] args) { System.out.println(new Cat().hashCode()); } //out //1349277854}
clone
java赋值是复制对象援用,如果咱们想要失去一个对象的正本,应用赋值操作是无奈达到目标的。Object对象有个clone()办法,实现了对
象中各个属性的复制,但它的可见范畴是protected的。
protected native Object clone() throws CloneNotSupportedException;
所以实体类应用克隆的前提是:
- 实现Cloneable接口,这是一个标记接口,本身没有办法,这应该是一种约定。调用clone办法时,会判断有没有实现Cloneable接口,没有实现Cloneable的话会抛异样CloneNotSupportedException。
- 笼罩clone()办法,可见性晋升为public。
public class Cat implements Cloneable { private String name; @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } public static void main(String[] args) throws CloneNotSupportedException { Cat c = new Cat(); c.name = "程序员大彬"; Cat cloneCat = (Cat) c.clone(); c.name = "大彬"; System.out.println(cloneCat.name); } //output //程序员大彬}
浅拷贝
拷⻉对象和原始对象的引⽤类型援用同⼀个对象。
以下例子,Cat对象外面有个Person对象,调用clone之后,克隆对象和原对象的Person援用的是同一个对象,这就是浅拷贝。
public class Cat implements Cloneable { private String name; private Person owner; @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } public static void main(String[] args) throws CloneNotSupportedException { Cat c = new Cat(); Person p = new Person(18, "程序员大彬"); c.owner = p; Cat cloneCat = (Cat) c.clone(); p.setName("大彬"); System.out.println(cloneCat.owner.getName()); } //output //大彬}
深拷贝
拷贝对象和原始对象的援用类型援用不同的对象。
以下例子,在clone函数中不仅调用了super.clone,而且调用Person对象的clone办法(Person也要实现Cloneable接口并重写clone办法),从而实现了深拷贝。能够看到,拷贝对象的值不会受到原对象的影响。
public class Cat implements Cloneable { private String name; private Person owner; @Override protected Object clone() throws CloneNotSupportedException { Cat c = null; c = (Cat) super.clone(); c.owner = (Person) owner.clone();//拷贝Person对象 return c; } public static void main(String[] args) throws CloneNotSupportedException { Cat c = new Cat(); Person p = new Person(18, "程序员大彬"); c.owner = p; Cat cloneCat = (Cat) c.clone(); p.setName("大彬"); System.out.println(cloneCat.owner.getName()); } //output //程序员大彬}
getClass
返回此 Object 的运行时类,罕用于java反射机制。
public class Person { private String name; public Person(String name) { this.name = name; } public static void main(String[] args) { Person p = new Person("程序员大彬"); Class clz = p.getClass(); System.out.println(clz); //获取类名 System.out.println(clz.getName()); } /** * class com.tyson.basic.Person * com.tyson.basic.Person */}
equals()和hashcode()的关系
equals与hashcode的关系:
1、如果两个对象调用equals比拟返回true,那么它们的hashCode值肯定要雷同;
2、如果两个对象的hashCode雷同,它们并不一定雷同。
hashcode办法次要是用来晋升对象比拟的效率,先进行hashcode()的比拟,如果不雷同,那就不用在进行equals的比拟,这样就大大减少了equals比拟的次数,当比拟对象的数量很大的时候能晋升效率。
之所以重写equals()要重写hashcode(),是为了保障equals()办法返回true的状况下hashcode值也要统一,如果重写了equals()没有重写hashcode(),就会呈现两个对象相等但hashcode()不相等的状况。这样,当用其中的一个对象作为键保留到hashMap、hashTable或hashSet中,再以另一个对象作为键值去查找他们的时候,则会查找不到。
==和equals区别
- 对于根本数据类型,==比拟的是他们的值。根本数据类型没有equal办法;
- 对于复合数据类型,==比拟的是它们的寄存地址(是否是同一个对象)。equals()默认比拟地址值,重写的话依照重写逻辑去比拟。
面向对象
面向对象个性
面向对象四大个性:封装,继承,多态,形象
- 封装就是将类的信息暗藏在类外部,不容许内部程序间接拜访,而是通过该类的办法实现对暗藏信息的操作和拜访。 良好的封装可能缩小耦合。
- 继承是从已有的类中派生出新的类,新的类继承父类的属性和行为,并能扩大新的能力,大大增加程序的重用性和易维护性。在Java中是单继承的,也就是说一个子类只有一个父类。
- 多态是同一个行为具备多个不同表现形式的能力。在不批改程序代码的状况下扭转程序运行时绑定的代码。
实现多态的三要素:继承、重写、父类援用指向子类对象。
动态多态性:通过重载实现,雷同的办法有不同的參数列表,能够依据参数的不同,做出不同的解决。
动静多态性:在子类中重写父类的办法。运行期间判断所援用对象的理论类型,依据其理论类型调用相应的办法。 - 形象。把客观事物用代码形象进去。
多态怎么实现
Java提供了编译时多态和运行时多态两种多态机制。编译时多态通过重载实现,依据传入参数不同调用不同的办法。运行时多态通过重写来实现,在子类中重写父类的办法,运行期间判断所援用对象的理论类型,依据其理论类型调用相应的办法。
类与对象
类class对一类事物的形容,是形象的、概念上的定义。类的构造包含属性和办法。
public class Person { //属性 private int age; private String name; //构造方法 public Person(int age, String name) { this.age = age; this.name = name; }}
对象是理论存在的该类事物的个体,也称为实例。
public class Person { private int age; private String name; public Person(int age, String name) { this.age = age; this.name = name; } public static void main(String[] args) { //p为对象 Person p = new Person(18, "程序员大彬"); }}
在Java中,万物皆对象,所有事物都能够看做对象。上述代码通过new关键字,创立了Person对象,p为对象的援用,p指向所创立的Person对象的内存地址。
属性
属性用来形容对象的状态信息,通常以变量的模式进行定义。变量分为成员变量和局部变量。
在类中,办法体之外定义的变量称为成员变量:
- 成员变量定义在类中,在整个类中都能够被拜访
- 成员变量分为类变量和实例变量,实例变量存在于每个对象所在的堆内存中。实例变量要创建对象后能力拜访。
- 成员变量有默认初始化值
- 成员变量的权限修饰符能够指定
定义在办法内,代码块内的变量称为局部变量:
- 局部变量存在于栈内存中
- 局部变量作用范畴完结,变量的内存空间回主动开释
- 局部变量没有默认值,每次必须显示初始化
- 局部变量申明时不指定权限修饰符
办法
形容的是对象的动作信息,办法也称为函数。
一般办法
一般通办法的语法结构:
[修饰符列表] 返回值类型 办法名(形参列表){ //办法体}
定义方法能够将性能代码进行封装。便于该性能进行复用。办法只有被调用才会被执行。
构造方法
构造方法是一种比拟非凡的办法,通过构造方法能够创建对象以及初始化实例变量。实例变量没有手动赋值的时候,零碎会赋默认值。
public class Person { //属性 private int age; private String name; //构造方法 public Person(int age, String name) { this.age = age; this.name = name; }}
办法重载
同个类中的多个办法能够有雷同的办法名称,然而有不同的参数列表,这就称为办法重载。参数列表又叫参数签名,包含参数的类型、参数的个数、参数的程序,只有有一个不同就叫做参数列表不同。
重载是面向对象的一个根本个性。
public class OverrideTest { void setPerson() { } void setPerson(String name) { //set name } void setPerson(String name, int age) { //set name and age }}
办法重写
办法的重写形容的是父类和子类之间的。当父类的性能无奈满足子类的需要,能够在子类对办法进行重写。
办法重写时, 办法名与形参列表必须统一。
如下代码,Person为父类,Student为子类,在Student中重写了dailyTask办法。
public class Person { private String name; public void dailyTask() { System.out.println("work eat sleep"); }}public class Student extends Person { @Override public void dailyTask() { System.out.println("study eat sleep"); }}
初始化程序
Java中类初始化程序:
- 动态属性,动态代码块。
- 一般属性,一般代码块。
- 构造方法。
public class LifeCycle { // 动态属性 private static String staticField = getStaticField(); // 动态代码块 static { System.out.println(staticField); System.out.println("动态代码块初始化"); } // 一般属性 private String field = getField(); // 一般代码块 { System.out.println(field); System.out.println("一般代码块初始化"); } // 构造方法 public LifeCycle() { System.out.println("构造方法初始化"); } // 静态方法 public static String getStaticField() { String statiFiled = "动态属性初始化"; return statiFiled; } // 一般办法 public String getField() { String filed = "一般属性初始化"; return filed; } public static void main(String[] argc) { new LifeCycle(); } /** * 动态属性初始化 * 动态代码块初始化 * 一般属性初始化 * 一般代码块初始化 * 构造方法初始化 */}
接口和抽象类
Java中接口和抽象类的定义语法别离为interface与abstract关键字。
抽象类
首先理解一下形象办法。形象办法是一种非凡的办法:它只有申明,而没有具体的实现。形象办法的格局为:
abstract void method();
形象办法必须用abstract关键字进行润饰。如果一个类含有形象办法,则称这个类为抽象类,抽象类必须在类前用abstract关键字润饰。因为抽象类中含有未实现的办法,所以不能用抽象类创建对象。
抽象类的特点:
- 抽象类不能被实例化只能被继承;
- 蕴含形象办法的肯定是抽象类,然而抽象类不肯定含有形象办法;
- 抽象类中的形象办法的修饰符只能为public或者protected,默认为public。
接口
接口对行为的形象。在Java中,定一个接口的模式如下:
public interface InterfaceName {}
接口中能够含有变量和办法。
接口的特点:
- 接口中的变量会被隐式指定为public static final类型,而办法会被隐式地指定为public abstract类型;
- 接口中的办法必须是形象办法,所有的办法不能有具体的实现;
- 一个类能够实现多个接口。
接口的用途
接口是对行为的形象,通过接口能够实现不相干类的雷同行为。通过接口能够晓得一个类具备哪些行为个性。
接口与抽象类区别
- 语法层面上
1)抽象类能够有办法实现,而接口的办法中只能是形象办法;
2)抽象类中的成员变量能够是各种类型的,接口中的成员变量只能是public static final类型;
3)接口中不能含有动态代码块以及静态方法,而抽象类能够有动态代码块和静态方法;
4)一个类只能继承一个抽象类,而一个类却能够实现多个接口。 设计层面上的区别
1)抽象层次不同。抽象类是对整个类整体进行形象,包含属性、行为,然而接口只是对类行为进行形象。继承抽象类是一种"是不是"的关系,而接口实现则是 "有没有"的关系。如果一个类继承了某个抽象类,则子类必然是抽象类的品种,而接口实现则是具备不具备的关系,比方鸟是否能飞。
2) 继承抽象类的是具备类似特点的类,而实现接口的却能够不同的类。门和警报的例子:
class AlarmDoor extends Door implements Alarm { //code}class BMWCar extends Car implements Alarm { //code}
反射
Java反射就是在运行状态中,对于任意一个类,都可能晓得这个类的所有属性和办法;对于任意一个对象,都可能调用它的任意办法和属性,并且能扭转它的属性。
作用:能够更灵便的编写代码,代码能够在运行时拆卸,无需在组件之间进行源代码链接,升高代码的耦合度;还有动静代理的实现等。须要留神的是反射使用不当会造成很高的资源耗费!
Class类
在Java中,每定义一个Java class实体都会产生一个Class对象。这个Class对象用于示意这个类的类型信息。
获取Class对象的三种形式:
//1、通过对象调用 getClass() 办法来获取,通常利用在:比方你传过来一个 Object// 类型的对象,而我不晓得你具体是什么类,用这种办法 Person p1 = new Person(); Class c1 = p1.getClass();//2、间接通过 类名.class 的形式失去,该办法最为安全可靠,程序性能更高// 这阐明任何一个类都有一个隐含的动态成员变量 class Class c2 = Person.class;//3、通过 Class 对象的 forName() 静态方法来获取,用的最多,// 但可能抛出 ClassNotFoundException 异样 Class c3 = Class.forName("com.ys.reflex.Person");
Class 类提供了一些办法,能够获取成员变量、成员办法、接口、超类、构造方法:
getName():取得类的残缺名字。 getFields():取得类的public类型的属性。 getDeclaredFields():取得类的所有属性。包含private 申明的和继承类 getMethods():取得类的public类型的办法。 getDeclaredMethods():取得类的所有办法。包含private 申明的和继承类 getMethod(String name, Class[] parameterTypes):取得类的特定办法,name参数指定办法的名字,parameterTypes 参数指定办法的参数类型。 getConstructors():取得类的public类型的构造方法。 getConstructor(Class[] parameterTypes):取得类的特定构造方法,parameterTypes 参数指定构造方法的参数类型。 newInstance():通过类的不带参数的构造方法创立这个类的一个对象。
Field类
Field提供了类和接口中字段的信息,通过Field类能够动静拜访这些字段。下图是Field类提供的一些办法。
Method类
Method类位于 java.lang.reflect 包中,次要用于在程序运行状态中,动静地获取办法信息。
Method类罕用的办法:
- getAnnotation(Class<T> annotationClass):如果该办法对象存在指定类型的注解,则返回该注解,否则返回null。
- getName():返回办法对象名称。
- isAnnotationPresent(Class<? extends Annotation> annotationClass):如果该办法对象上有指定类型的注解,则返回true,否则为false。
- getDeclaringClass ():返回该办法对象示意的办法所在类的Class对象。
- getParameters():返回一个参数对象数组,该数组示意该办法对象的所有参数。
- getReturnType():返回一个Class对象,该Class对象示意该办法对象的返回对象,会擦除泛型。
泛型
泛型的实质是参数化类型,也就是说所操作的数据类型被指定为一个参数。编译时会进行类型擦除。在泛型应用过程中,操作的数据类型被指定为一个参数,这种参数类型能够用在类、接口和办法中,别离被称为泛型类、泛型接口、泛型办法。
泛型类
泛型类型用于类的定义中,被称为泛型类。通过泛型能够实现对一组类的操作对外开放雷同的接口。最典型的就是各种容器类,如:List、Set、Map。
泛型类示例:
//此处T能够轻易写为任意标识,常见的如T、E、K、V等模式的参数罕用于示意泛型//在实例化泛型类时,必须指定T的具体类型public class Generic<T>{ //key这个成员变量的类型为T,T的类型由内部指定 private T key; public Generic(T key) { //泛型构造方法形参key的类型也为T,T的类型由内部指定 this.key = key; } public T getKey(){ //泛型办法getKey的返回值类型为T,T的类型由内部指定 return key; }}
泛型类的应用:
@Slf4jpublic class GenericTest { public static void main(String[] args) { //泛型的类型参数只能是类类型(包含自定义类),不能是简略类型 //传入的实参类型需与泛型的类型参数类型雷同,即为Integer. Generic<Integer> genericInteger = new Generic<Integer>(666); //传入的实参类型需与泛型的类型参数类型雷同,即为String. Generic<String> genericString = new Generic<String>("程序员大彬"); log.info("泛型测试: key is {}", genericInteger.getKey()); log.info("泛型测试: key is {}", genericString.getKey()); } /** * output * 23:51:55.519 [main] INFO com.tyson.generic.GenericTest - 泛型测试: key is 666 * 23:51:55.526 [main] INFO com.tyson.generic.GenericTest - 泛型测试: key is 程序员大彬 */}
泛型接口
泛型接口与泛型类的定义及应用基本相同。
//定义一个泛型接口public interface Generator<T> { public T next();}
泛型办法
泛型类,是在实例化类的时候指明泛型的具体类型;泛型办法,是在调用办法的时候指明泛型的具体类型 。
@Slf4jpublic class GenericMethod { /** * 泛型办法的根本介绍 * @param t 传入的泛型实参 * @return T 返回值为T类型 * 阐明: * 1)public 与 返回值两头<T>十分重要,能够了解为申明此办法为泛型办法。 * 2)只有申明了<T>的办法才是泛型办法,泛型类中的应用了泛型的成员办法并不是泛型办法。 * 3)<T>表明该办法将应用泛型类型T,此时才能够在办法中应用泛型类型T。 * 4)与泛型类的定义一样,此处T能够轻易写为任意标识,常见的如T、E、K、V等模式的参数罕用于示意泛型。 */ public <T> void genericMethod(T t) { log.info(t.toString()); } public static void main(String[] args) { GenericMethod genericMethod = new GenericMethod(); genericMethod.genericMethod("程序员大彬"); genericMethod.genericMethod(666); } /** * output * 23:59:11.906 [main] INFO com.tyson.generic.GenericMethod - 程序员大彬 * 23:59:11.912 [main] INFO com.tyson.generic.GenericMethod - 666 */}
Exception
在 JAVA 语言中,将程序执行中产生的不失常状况称为异样。异样是程序常常会呈现的状况,发现错误的最佳时机是在编译阶段,也就是运行程序之前。
所有异样都继承了 Throwable。
Throwable
Throwable类是Error和Exception的父类,只有继承于Throwable的类或者其子类能力被抛出。Throwable分为两类:
Error:JVM 无奈解决的重大问题,如栈溢出(StackOverflowError)、内存溢出(OOM)等。程序无奈解决的谬误。
栈溢出:如下代码递归调用main,最终会抛出StackOverflowError。
public class Test { public static void main(String[] args) { main(args); } /** * Exception in thread "main" java.lang.StackOverflowError */}
内存溢出OOM:上面的代码中,新建了一个数组,数组长度是 1G,又因为是 Integer 包装类型,一个元素占 4 个字节,所以,这个数组占用内存 4GB。最初,堆内存空间有余,抛出了 OOM。
public class Test { public static void main(String[] args) { Integer[] arr = new Integer[1024 * 1024 * 1024]; } /** * Exception in thread "main" java.lang.OutOfMemoryError: Java heap space */}
- Exception:其它因编程谬误或偶尔的外在因素导致的一般性问题。能够在代码中进行解决。如:空指针异样、数组下标越界等。
unchecked exception包含RuntimeException和Error类,其余所有异样称为查看(checked)异样。
运行时异样和非运行时异样(checked)的区别:
- RuntimeException由程序谬误导致,应该修改程序防止这类异样产生。
- checked Exception由具体的环境(读取的文件不存在或文件为空或sql异样)导致的异样。必须进行解决,不然编译不通过,能够catch或者throws。
常见的Exception
常见的RuntimeException:
ClassCastException //类型转换异样IndexOutOfBoundsException //数组越界异样NullPointerException //空指针ArrayStoreException //数组存储异样NumberFormatException //数字格式化异样ArithmeticException //数学运算异样
unchecked Exception:
NoSuchFieldException //反射异样,没有对应的字段ClassNotFoundException //类没有找到异样IllegalAccessException //平安权限异样,可能是反射时调用了private办法
关键字
- throw:用于抛出一个具体的异样对象。
- throws:用在办法签名中,用于申明该办法可能抛出的异样。子类办法抛出的异样范畴更加小,或者基本不抛异样。
- try:用于监听。将可能抛出异样的代码放在try语句块之中,当try语句块内产生异样时,异样就被抛出。
- catch:用于捕捉异样。
- finally:finally语句块总是会被执行。它次要用于回收在try块里关上的资源(如数据库连贯、网络连接和磁盘文件)。
如下代码示例,除以0抛出异样,产生异样之后的代码不会执行,间接跳到catch语句块执行,最初执行finally语句块。
public class ExceptionTest { public static void main(String[] args) { try { int i = 1 / 0; System.out.println(i + 1); } catch (Exception e) { System.out.println(e.getMessage()); } finally { System.out.println("run finally..."); } } /** * / by zero * run finally... */}
IO流
Java IO流的外围就是对文件的操作,对于字节 、字符类型的输出和输入流。IO流次要分为两大类,字节流和字符流。字节流能够解决任何类型的数据,如图片,视频等,字符流只能解决字符类型的数据。
图片参考:Java io学习整顿
InputStream 和 OutputStream
InputStream 用来示意那些从不同数据源产生输出的类。这些数据源包含:1.字节数组;2.String 对象;3.文件;4.管道;5.一个由其余品种的流组成的序列。
InputStream 类有一个形象办法:abstract int read()
,这个办法将读入并返回一个字节,或者在遇到输出源结尾时返回-1。
OutputStream 决定了输入所要去的指标:字节数组、文件或管道。OutputStream 的 abstract void write(int b)
能够向某个输入地位写出一个字节。
read() 和 write() 办法在执行时都将阻塞,期待数据被读入或者写出。
罕用的字节流有FileInputStream、FileOutputStream、ObjectInputStream、ObjectOutputStream。
Reader 和 Writer
字符流是由通过字节流转换失去的,转化过程耗时,而且容易呈现乱码问题。I/O 流提供了一个间接操作字符的接口,不便咱们平时对字符进行流操作。如果音频文件、图片等媒体文件用字节流比拟好,如果波及到字符的话应用字符流比拟好。
abstract int read();abstract void write(char c);
字符流和字节流的转换
InputStreamReader:字节到字符的转换,可对读取到的字节数据通过指定编码转换成字符。
OutputStreamWriter:字符到字节的转换,可对读取到的字符数据通过指定编码转换成字节。
同步异步
同步:收回一个调用时,在没有失去后果之前,该调用就不返回。
异步:在调用收回后,被调用者返回后果之后会告诉调用者,或通过回调函数解决这个调用。
阻塞非阻塞
阻塞和非阻塞关注的是线程的状态。
阻塞调用是指调用后果返回之前,以后线程会被挂起。调用线程只有在失去后果之后才会复原运行。
非阻塞调用指在不能立即失去后果之前,该调用不会阻塞以后线程。
举个例子,了解下同步、阻塞、异步、非阻塞的区别:
同步就是烧开水,要本人来看开没开;异步就是水开了,而后水壶响了告诉你水开了(回调告诉)。阻塞是烧开水的过程中,你不能干其余事件,必须在旁边等着;非阻塞是烧开水的过程里能够干其余事件。
BIO
同步阻塞I/O模式,数据的读取写入必须阻塞在一个线程内期待其实现。
NIO
NIO是一种同步非阻塞的I/O模型,在Java 1.4 中引入了 NIO 框架,对应 java.nio 包,提供了 Channel , Selector,Buffer等形象。
NIO与IO区别:
- IO是面向流的,NIO是面向缓冲区的;
- IO流是阻塞的,NIO流是不阻塞的;
- NIO有选择器,而IO没有。
Buffer:Buffer用于和Channel交互。从Channel中读取数据到Buffer里,从Buffer把数据写入到Channel。
Channel:NIO 通过Channel(通道) 进行读写。通道是双向的,可读也可写,而流的读写是单向的。无论读写,通道只能和Buffer交互。
Selector:应用更少的线程来就能够来解决通道了,相比应用多个线程,防止了线程上下文切换带来的开销。
AIO
异步非阻塞 IO。异步 IO 是基于事件和回调机制实现的,也就是利用操作之后会间接返回,不会梗塞在那里,当后盾解决实现,操作系统会告诉相应的线程进行后续的操作。
BIO/NIO/AIO区别
同步阻塞IO : 用户过程发动一个IO操作当前,必须期待IO操作的真正实现后,能力持续运行。
同步非阻塞IO: 客户端与服务器通过Channel连贯,采纳多路复用器轮询注册的Channel。进步吞吐量和可靠性。用户过程发动一个IO操作当前,可做其它事件,但用户过程须要轮询IO操作是否实现,这样造成不必要的CPU资源节约。
异步非阻塞IO: 非阻塞异步通信模式,NIO的升级版,采纳异步通道实现异步通信,其read和write办法均是异步办法。用户过程发动一个IO操作,而后立刻返回,等IO操作真正的实现当前,应用程序会失去IO操作实现的告诉。类比Future模式。
文章很长,花了挺长时间整顿的,如果感觉对你有帮忙,能够点个赞激励一下~
我是程序员大彬,专一Java后盾开发常识分享,欢送大家关注~