源代码组织方式
Java程序由package+class组成,package对应目录的相对路径。
1 packagecom.happyframework.javastudy.hello;2 3 public final class Hello {4 public static void hello(){5 System.out.println("hello!");6 }7 }
关于class有如下几点规则:
文件的名字必须和class的名字一致(public级别的class名字)。
文件必须只包含一个public访问基本的class(可以包含多个非public级别的class)。
package名字必须和目录一致。
入口方法
App.java
1 public class App {2 public static void main(String[] args) {3 com.happyframework.javastudy.hello.Hello.hello();4 }5 }
”我自己是一名从事了十余年的后端的老程序员,辞职后目前在做讲师,近期我花了一个月整理了一份最适合2018年学习的JAVA干货(里面有高可用、高并发、高性能及分布式、Jvm性能调优、Spring源码,MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多个知识点的架构资料)从事后端的小伙伴们都可以来了解一下的,这里是程序员秘密聚集地,各位还在架构师的道路上挣扎的小伙伴们速来。“
加QQ群:611481448(名额有限哦!)
最终的项目结构
数据类型
8种原子类型
整数类型:byte、short、int和long。
小数类型:float和double。
字符类型:char。
布尔类型:bool。
除此之外的是interface、class和array。
小数类型的常量默认是double类型,声明float类型的常量需要使用F作为后缀。
1public class Program {23/**
4 * @param args
5 */6public static void main(String[] args) {7floatage =28.0F;8System.out.println(age);9}1011}
运算符
算术运算符:+、-、*、/ 和 %,两个整数相除,结果还是整数。
赋值运算符:=、+=、-=、*=、/=、%=、&=、|=、~=、^=、<<=、>>= 、 >>>=、++ 和 --。
比较运算符:==、!=、<、<=、> 和 >=。
逻辑运算符:&&、|| 和 !。
位运算符:&、|、~、^、<<、>> 和 >>>。
字符串
String是拥有“值语义”的引用类型,字符串常量实现了“享元模式”,equals会按照内容进行比较,==按照地址比较。
1public class Program {23/**
4 * @param args
5 */6public static void main(String[] args) {7String x ="段光伟";8String y = new String("段光伟");910System.out.println(x.equals(y));// true11System.out.println(x == y);// false12}1314}
为了高效的修改字符串Java引入了StringBuffer。
1 {2 StringBuffer sb =3 newStringBuffer()4 .append("段")5 .append("光")6 .append("伟");7 8 System.out.println(sb.toString());9 }
数组
声明语法
DataType[] name 或 DataType name[]。
初始化语法
DataType[] name = new DataType[length]。
DataType[] name = new DataType[] { element1, element2, ...elementn }。
DataType[] name = { element1, element2, ...elementn }。
1publicclass Program {23/**
4 * @param args
5 */6publicstaticvoidmain(String[] args) {7{8String[] strs = {"段","光","伟"};910for(Stringitem : strs) {11System.out.print(item);12}13}14}1516}
多维数组
只有不等长多维数组DataType[][],没有DataType[xxx, xxx]。
控制结构
条件:if-else if-else、switch-case-default和三元运算符(?:)。
循环:while、do-while、for和foreach。
Labeled block。
1publicclassProgram{23/**
4 * @param args
5 */6publicstaticvoidmain(String[] args){7task: {8intage =25;910System.out.println("start");1112if(age <30) {13breaktask;14}1516System.out.println("end");17}18}19}
最近觉得label是个不错的东西,最起码多了一种选择。
方法
Java中所有的赋值和方法调用都是“按值“处理的,引用类型的值是对象的地址,原始类型的值是其自身。
Java支持变长方法参数。
1publicclass Program {23/**
4 * @param args
5 */6publicstaticvoidmain(String[] args) {7print("段光伟","段光宇");8print(newString[] {"段光伟","段光宇"});9}1011privatestaticvoidprint(String... args) {12for(Stringitem : args) {13System.out.println(item);14}15}16}
类
1publicclassProgram{23/**
4 * @param args
5 */6publicstaticvoidmain(String[] args){7Point point =newPoint(100);89System.out.print(point);10}11}1213classPoint{14privateintx =0;15privateinty =0;1617publicPoint(intx,inty){18this.x = x;19this.y = y;20}2122publicPoint(intx){23this(x, x);24}2526publicStringtoString(){27return"(x:"+this.x +",y:"+this.y +")";28}29}
注意:调用自身的构造方法是用this(xxx,xxx,...)来完成,且必须位于第一行。
静态成员
Java中类似静态构造方法的结构,称之为:静态初始化代码块,与之对应的是实例初始化代码块,见下例:
1public class Program {23/**
4 * @param args
5 */6public static void main(String[] args) {7System.out.println(Point.getValue());8System.out.println(new Point());9}10}1112class Point {13private static int value =0;1415public static int getValue() {16return value;17}1819static {20value++;21}2223static {24value++;25}2627private int x =0;28private int y =0;2930{31this.x =10;32}3334{35this.y =10;36}3738public String toString() {39return"(x:"+ this.x +",y:"+ this.y +")";40}41}
继承
继承使用 extends,抽象类和抽象方法使用abstract声明,向下转型使用 (ChildType)instance,判断是否是某个类型使用 instanceof,见下例:
1public class Program {23/**
4 * @param args
5 */6public static void main(String[] args) {7printAnimal(new Animal());8printAnimal(new Dog());9}1011private static void printAnimal(Animal animal) {12if(animal instanceof Dog){13System.out.println("I am a "+ (Dog) animal);14}15else16{17System.out.println("I am an "+ animal);18}19}20}2122class Animal {23public String toString() {24return"Animal";25}26}2728class Dog extends Animal {29public String toString() {30return"Dog";31}32}
重写
Java中的重写规则比较灵活,具体如下:
除了 private 修饰之外的所有实例方法都可以重写,不需要显式的声明。
重写的方法为了显式的表达重写这一概念,使用 @Override进行注解。
重写的方法可以修改访问修饰符和返回类型,只要和父类的方法兼容(访问级别更高,返回类型更具体)。
可以使用final将某个方法标记为不可重写。
在构造方法中使用 super(xxx, xxx)调用父类构造方法,在常规实例方法中使用 super.method(xxx, xxx)调用父类方法。
Java不支持覆盖(new)。
1public class Program {23/**
4 * @param args
5 */6public static void main(String[] args) {7Animal animal = new Animal();8Animal dog = new Dog();910animal.say();11dog.say();1213animal.eat(animal);14dog.eat(dog);1516System.out.println(animal.info());17System.out.println(dog.info());18}19}2021class Animal {22private String name ="Animal";2324protected void say() {25System.out.println("Animal"+" "+ this.name);26}2728public void eat(Animal food) {29System.out.println("Animal eat "+ food);30}3132public Object info() {33return"Animal";34}3536@Override37public String toString() {38return"Animal";39}40}4142class Dog extends Animal {43private String name ="Dog";4445@Override46public final void say() {47System.out.println("Dog"+" "+ this.name);48}4950@Override51public final void eat(Animal food) {52super.eat(food);5354System.out.println("Dog eated");55}5657@Override58public final String info() {59return"Dog";60}6162@Override63public final String toString() {64return"Dog";65}66}
包
包的名字和项目路径下的目录路径相对应,比如:项目路径为:C:\Study,有一个Java源文件位于:C:\Study\com\happyframework\study\App.java,那么App.java的包名字必须为:com.happyframework.study,且 App.java 的第一行语句必须为:package com.happyframework.study。
Java支持三种导入语法:
导入类型:import xxx.xxx.xxxClass。
导入包:import xxx.xxx.xxx.*。
导入静态成员:import static xxx.xxx.*。
1importstaticutil.Helper.*;23publicclassProgram{45/**
6 * @param args
7 */8publicstaticvoidmain(String[] args){9puts("段光伟");10}11}
访问级别
Java支持四种访问级别:public、private、protected 和 default(默认),类型和接口只能使用public 和 default,成员和嵌套类型可以使用所有,下面简单的解释一下 protected 和 default。
protected 修饰过的成员只能被自己、子类和同一个包里的(不包括子包)其他类型访问。
default 修改过的类型或成员只能被自己和同一个包里的(不包括子包)其他类型访问。
嵌套类
Java支持如下几种嵌套类:
nested class,定义在类型内部的类型。
static nested class,使用 static 声明的 nested class,static nested class 可以访问所有外部类的静态成员。
inner class,没有使用 static 声明的 nested class,inner class 可以访问所有外部类的实例成员,inner class 不能定义静态成员。
代码示例
1public class Program {23/**
4 * @param args
5 */6public static void main(String[] args) {7OuterClass outer = new OuterClass();8OuterClass.InnerClass inner = outer.new InnerClass();9OuterClass.InnerClass.InnerInnerClass innerInner = inner.new InnerInnerClass();10outer.show();11inner.show();12innerInner.show();1314OuterClass.StaticNestedClass staticNested=new OuterClass.StaticNestedClass();15OuterClass.StaticNestedClass.StaticNestedNestedClass staticNestedNested=new OuterClass.StaticNestedClass.StaticNestedNestedClass();1617staticNested.show();18staticNestedNested.show();19}20}2122class OuterClass {23int x =1;24static int i =1;2526void show() {27System.out.println(x);28System.out.println(i);29}3031class InnerClass {32int y =2;3334void show() {35System.out.println(x);36System.out.println(y);37}3839class InnerInnerClass {40int z =3;4142void show() {43System.out.println(OuterClass.this.x);44System.out.println(y);45System.out.println(z);46}47}48}4950static class StaticNestedClass {51static int j =2;5253void show() {54System.out.println(i);55System.out.println(j);56}5758static class StaticNestedNestedClass {59static int k =3;6061void show() {62System.out.println(i);63System.out.println(j);64System.out.println(k);65}66}67}68}
特殊的inner class:local class
1public class LocalClassExample {23static String staticValue ="static value";4String instanceValue ="instance value";56public void test() {78final String finalLocalValue ="final local value";910class LocalClass {11void test() {12System.out.println(staticValue);13System.out.println(instanceValue);14System.out.println(finalLocalValue);15}16}1718LocalClass local = new LocalClass();19local.test();20}21}
除了inner class的规则之外,local class可以访问局部final变量,在Java8中有更多的改进。
特殊的local class:anonymous class
1public class Program {23/**
4 * @param args
5 */6public static void main(String[] args) {7execute(new Action() {8@Override9public void execute() {10System.out.println("执行业务逻辑");11}12});13}1415static void execute(Action action) {16System.out.println("事物开始");17action.execute();18System.out.println("事物结束");19}20}2122interface Action {23void execute();24}
常量
不废话了,直接看代码:
1publicfinalclass Program {2staticfinalStringSTATIC_CONSTANTS ="STATIC_CONSTANTS";3finalStringINSTANCE_CONSTANTS ="INSTANCE_CONSTANTS";45publicstaticvoidmain(String[] args) {6finalStringLOCAL_CONSTANTS ="LOCAL_CONSTANTS";78System.out.println(STATIC_CONSTANTS);9System.out.println(newProgram().INSTANCE_CONSTANTS);10System.out.println(LOCAL_CONSTANTS);11newProgram().test("PARAMETER_CONSTANTS");12}1314publicfinalvoidtest(finalStringmsg) {15System.out.println(msg);16}17}
有一点需要注意的是:只有一种情况Java的常量是编译时常量(编译器会帮你替换),其它情况都是运行时常量,这种情况是:静态类型常量且常量的值可以编译时确定。
接口
Java的接口可以包含方法签名、常量和嵌套类,见下例:
1public final class Program {2public static void main(String[] args) {3Playable.EMPTY.play();45new Dog().play();6}7}89interface Playable {10Playable EMPTY = new EmptyPlayable();1112void play();1314class EmptyPlayable implements Playable {1516@Override17public void play() {18System.out.println("无所事事");19}2021}22}2324class Dog implements Playable {2526@Override27public void play() {28System.out.println("啃骨头");29}3031}
枚举
Java枚举是class,继承自java.lang.Enum,枚举中可以定义任何类型可以定义的内容,构造方法只能是private或package private,枚举成员会被编译器动态翻译为枚举实例常量,见下例:
1publicfinalclassProgram{2publicstaticvoidmain(String[] args){3System.out.println(State.ON);4System.out.println(State.OFF);56for(State item : State.values()) {7System.out.println(item);8System.out.println(State.valueOf(item.name()));9}10}11}1213enumState {14ON(1), OFF(0);1516intvalue=1;1718State(intvalue) {19this.value=value;20}21}
调用枚举的构造方法格式是:常量名字(xxx, xxx),如果构造方法没有参数只需要:常量名子,如:
1 enum State {2 ON,OFF3 }
异常
Java中的异常分为checked和unchecked,checked异常必须声明在方法中或被捕获,这点我觉得比较好,必定:异常也是API的一部分,见下例:
1publicfinalclassProgram{2publicstaticvoidmain(String[] args){3try{4test();5}catch(Exception e) {6System.out.println(e.getMessage());7}8}910publicstaticvoidtest()throwsException{11thrownewException("I am wrong!");12}13}
所有继承Exception的异常(除了RuntimeException和它的后代之外)都是checked异常。
装箱和拆箱
Java提供了原始类型对应的引用类型,在1.5之后的版本还提供了自动装箱和自动拆箱,结合最新版本的泛型,几乎可以忽略这块。
1import java.util.*;23public final class Program {4public static void main(String[] args) {5ArrayListlist= new ArrayList();67list.add(1);8int item1 = (Integer)list.get(0);910System.out.println(item1);11}12}
注意:自动装箱和自动拆箱是Java提供的语法糖。
泛型
Java的泛型是编译器提供的语法糖,官方称之为:类型参数搽除,先看一下语法,然后总结一点规律:
泛型方法
测试代码
1staticvoidputs(T msg) {2println(msg);3}45staticvoidprintln(Objectmsg) {6System.out.println("Object:"+ msg);7}89staticvoidprintln(Stringmsg) {10System.out.println("String:"+ msg);11}
调用泛型方法
1 System.out.println("generic method test");2 puts("hello");3 Program. puts("hello");
输出的结果是
1 generic method test2 Object:hello3 Object:hello
泛型类
测试代码
1 class TestGenericClass {2 T value;3 4 void setValue(T value) {5 this.value = value;6 }7 }
调用代码
1 System.out.println("generic class test");2 System.out.println(t.value);
输出结果
1 generic class test2 1
泛型接口
测试代码
1interfaceTestInterface{2voidtest(T item);3}45classTestInterfaceImp1implementsTestInterface{67@Override8publicvoidtest(String item){9System.out.println(item);10}11}1213classTestInterfaceImp2implementsTestInterface{1415@Override16publicvoidtest(T item){17System.out.println(item);18}19}
调用代码
1System.out.println("generic interface test");2TestInterface testInterface1 =newTestInterfaceImp1();3testInterface1.test("hi");4for(Method item : testInterface1.getClass().getMethods()) {5if(item.getName() =="test") {6System.out.println(item.getParameterTypes()[0].getName());7}8}910TestInterface testInterface2 =newTestInterfaceImp2<>();11testInterface2.test("hi");12for(Method item : testInterface2.getClass().getMethods()) {13if(item.getName() =="test") {14System.out.println(item.getParameterTypes()[0].getName());15}16}
输出结果
1 generic interface test2 hi3 java.lang.String4 java.lang.Object5 hi6 java.lang.Object
类型参数约束
测试代码
1classAnimal{2}34classDogextendsAnimal{5}67classBase
调用代码
1 System.out.println("bounded type parameters test");2 Basebase=newChild();3 base.test(newDog());4 for(Method item :base.getClass().getMethods()) {5 if(item.getName() =="test") {6 System.out.println(item.getParameterTypes()[0].getName());7 }8 }
输出结果
1 bounded type parameters test2 Child:Dog@533c2ac33 Dog4 Animal
类型搽除过程
将泛型定义中的类型参数去掉。
classBase{publicvoidtest(T item){ System.out.println("Base:"+ item); }}
将T换成extends指定的约束类型,默认是Object。
1 classBase{2 public void test(Animal item) {3 System.out.println("Base:"+ item);4 }5 }
如果有非泛型类型继承或实现了泛型基类或接口,而且进行了重写,根据情况,编译器会自动生成一些方法。
1classChildextendsBase{2@Override3public void test(Animalitem) {4this.test((Dog)item);5}67public void test(Dogitem) {8System.out.println("Child:"+ item);9}10}
根据泛型参数的实际参数搽除调用代码。
1 System.out.println("bounded type parameters test");2 Basebase=newChild();3 base.test(newDog());4 for(Method item :base.getClass().getMethods()) {5 if(item.getName() =="test") {6 System.out.println(item.getParameterTypes()[0].getName());7 }8 }
这里说的不一定正确,特别是Java泛型的约束支持&(如:可以约束实行多个接口),不过过程估计差别不大,我没有看Java语言规范,这里只是大概的猜测。