1.包
package
package语法:包名.类名 ;包名的写法规范:所有字母需小写。
当然也可以采用静态导入 例如 import static java.lang.Math.*
有包的对象不能使用默认包的对象。
import
java.lang 包是java虚拟机自动导入的包,在使用java.lang包时我们可以不需要导包;例如:Thread类,Exception类,System类,String类等,可以相应的查看Api。
java.util.* 这里的*表示java.util下的所有匹配的类,但是不会导致类的初始化(原因见后续浅析加载和垃圾清理机制),一般情况下不建议这么去做,会增加系统负担,且package和import语句的顺序是固定的,pakage必须位于第一行。
2.Java语言的4种控制权限
public:对外公开,访问权限最高;可修饰对象,方法和属性
proteted:对同一包中的类或者子类公开;可修饰一般方法,抽象类的抽象方法,属性,一般类的构造方法;
默认:对同一包中公开;可修饰类,接口,抽象类,一般方法,抽象类的抽象方法,属性,一般类的构造方法。
private:不对外公开,只能内部访问(但是可以通过反射去除权限后强制访问,见后续反射);可修饰一般方法,属性,一般类的构造方法。
注意:类,抽象类等的方法及属性权限不会高于类,接口抽象类等的权限,但书写过程中方法及属性权限高于类,抽象类等的权限,在javac编译的过程中不会产生编译错误,java运行时也不会报错,这样书写没有实际的意义。
3.对象的声明
1)类
类的声明
语法:[final]+ public/默认+class+类名。
2)抽象类
抽象类的声明
语法:public/默认+ abstract +class+类名;其中可以含有抽象方法和非抽象方法,该类不能被new,为多态提供实现。
3)枚举(见后续枚举)
枚举的声明
语法:public+enum+类名。
4)接口
接口的声明
语法:public/默认 +interface+类名,接口中所有的方法和成员属性及静态内部类只能由public权限来修饰(包括static和default修饰的具有方法体的方法),在没有添加static和default方法的前提下,默认都会补全public abstract修饰成为公有的抽象方法,static和default修饰普通方法的前提下可以有方法体存在(jdk1.8及以上版本,没有添加权限的时候默认添加public),在接口中的成员属性为固定的方式final public static+类型+全局变量名存在(没写完整,默认会补全),接口不能被new,不存在static{},不能存在{},为多态提供实现。
6.类的组成部分(属性和方法)
1)变量的声明
1>成员变量的声明:
语法: [final]+ private/默认/protected/public +[static]+[transiernt(见后续io)]+[volatile(见后续多线程)]+类型+全局变量名,(在接口中的定义方式为固定的方式final public static+类型+变量名)
2>局部变量的声明
[final]+类型+变量名
2)方法的声明
1>一般方法的声明
语法:[ final]+ private/默认/protected/public+[static]+[<T>(泛型声明)] + synchronized +[native(声明这个方法是由c/c++/fortran编写的,不能有方法体,不能有泛型)]+返回值类型/void(无返回值)+方法名,假如有返回值,那么在方法体中需要添加return +返回类型的结果,在void情况下,程序会在后续默认的添加return,当然也可以自己来添加return
2>抽象方法的声明:
语法: [protected/public](默认不写表示在重写方法的时候可以指定为protected或者是public) +abstract+ 返回值类型/void(无返回值)+方法名;注意:没有方法体,在接口中的抽象方法修饰权限都必须为public权限(默认不写会自动添加public abstract),在子类中需重写,在重写的时候可以添加final ,synchronized来修饰重写的方法,不能用static修饰,抽象方法不能与static和final修饰共存
3)构造方法的声明
1>无参构造:在没有构造方法的前提下,默认会自动添加无参构造方法,假如重载了构造方法则不会默认添加,语法:private/默认/protected/public +类名(),注意:被private修饰后不能被其它类利用此构造器对此进行初始化,一般都会有public的无参构造便于后续框架等利用反射对其的调用,不能被其他修饰符修饰
2>有参构造方法:语法:private/默认/protected/public +类名(参数);不能被其他修饰
4)代码块
1>静态代码块
语法:static{},可以用于类,抽象类作为成员,不能用于接口,只运行一次,常用作初始化
2>代码块
语法:{}可以用于作为类,抽象类成员,也可以用于局部,不可以用于接口成员,可运行多次
执行顺序:见如下代码(这里只提出问题和总结,并不做出解析,原因请见下一篇浅析类加载和垃圾回收机制)
public class Father {
static int p = 10;
static{
System.out.println("父类静态初始化块");
}
}
public class Son extends Father{
static{
System.out.println("子类静态初始化块");
}
}
public class Test {
public static void main(String[] args) {
System.out.println(Son.p);
}
}//输出结果依次为父类静态初始化块,10
public class Father {
static int p = 10;
{
System.out.println("父类代码块");
}
static{
System.out.println("父类静态初始化块");
}
}
public class Son extends Father{
static int c = 20;
static{
System.out.println("子类静态初始化块");
}
{
System.out.println("子类代码块");
}
public static void main(String[] args) {
Son son = new Son();
}
} //输出结果依次为父类静态初始化块,子类静态初始化块,父类代码块,子类代码块
public class Father {
static int p = 10;
static{
System.out.println("父类静态初始化块");
}
}
public interface Uncle {
String str=Test.testImp();
}
public class Son extends Father implements Uncle {
static int c = 20;
static {
System.out.println("子类静态初始化块");
}
}
public class Test {
static String testImp() {
System.out.println("我是从test方法中输出");
return "我是test返回的结果 ";
}
public static void main(String[] args) {
System.out.println(Son.p);
}
}//输出结果依次为父类静态初始化块,10,在接口中的变量你不主动去掉用那么是不会被加载的,当主动调用的是接口的话,那么无需初始化该类,不会初始化父类
public interface Father {
String father=Test.testImp("我是father");
}
public interface Son extends Father {
String son=Test.testImp("我是son");
}
public class Test {
static String testImp(String str) {
System.out.println(str);
return str+"的结果 ";
}
public static void main(String[] args) {
System.out.println(Son.son);
}
}//输出结果依次为我是son,我是son的结果
public class Test {
public static void test() {
System.out.println("我是静态方法");
}
{
System.out.println("我是构造代码块");
}
static {
System.out.println("我是静态代码块");
}
public static void main(String[] args) {
test();
}
}//我是静态代码块 我是静态方法
总结:综合上述我们可以知道,首先运行的是父类的静态属性和静态代码(按顺序),然后是子类的静态属性和静态代码(按顺序),然后是父类的代码块,然后是子类的代码块,然后是父类的构造方法,然后是子类的构造方法,没实例化不会运行构造方法和代码块,接口不会初始化继承的父类接口及类不会初始化实现的接口(但是调用了接口中的变量,那么会相应的调用的本身部分(在常量池中自身调用),不会初始化及调用其它部分,所以接口是一个特殊的存在),子类使用父类的静态方法不会初始化子类的静态代码块和静态属性(前提是不写在子类的main方法中,写在main方法中,全部都会被初始化),感觉是不是懂了,再给一个实例,看看输出结果是什么
public class Test {
private final static Test test = new Test();
private static Map<String, String> map = null;
static {
map = new HashMap<>();
map.put("0", "北京");
}
public Test() {
init();
}
public static void init() {
if (map == null) {
System.out.println("问题出现了");
map=new HashMap<>();
}
map.put("1", "上海");
map.put("2", "深圳");
}
public Map getMap() {
return Collections.unmodifiableMap(map);
}
public static Test getTest() {
return test;
}
public static void main(String[] args) {
System.out.println(Test.getTest().getMap());
}
}//输出结果 问题出现了 {0=北京}
看看下面的或许你就明白了
public class Test {
private static Test test = new Test();
static {
System.out.println("静态代码块");
}
{
System.out.println("代码块");
}
public Test() {
System.out.println("初始化");
}
public static void main(String[] args) {
}
}//代码块 初始化 静态代码块
总结:静态属性和静态代码块依次执行,所以private static Test test = new Test();会先执行,这里的new是实例的初始化,而类的初始化顺序是在调用main方法时进行类的初始化,且static只运行一次,所以在new之前执行的顺序就已经确定
public class Test {
static {
System.out.println("静态代码块");
}
public static void main(String[] args) {
}
}//静态代码块
5.final 关键字
final:可修饰类,一般方法,变量,被final修饰的类是一个最终类,不可以被继承;被final修饰的方法是一个最终方法,不可以被覆盖;被final修饰的变量是一个常量,只能赋值一次,在接口中的成员属性为固定的方式final public static+类型+全局变量名。(final和public等权限及static的顺序是可以调动的 ),被final修饰的处于常量池中,不可以修饰抽象方法,构造方法,接口,抽象类,stirng类就是一个常量类,不能被继承,如包装类。
6.this和supper关键字
this表示该对象,不可以在静态方法中使用 。(原因是静态部分在实例化之前加载,对this和super并不识别)
super表示父对象,不可以在静态方法中使用。
注意:super默认会添加在该类构造方法第一行,且顺序不能变,也就是说初始化该类的时候保证先初始化父类。
7.注释
// 单行注释 会被javac忽略
/* */ 多行注释 会被javac忽略
/** */ 多行注释 会被javac忽略,但是会作为javadoc文档的说明(见后续javadoc)
8.面对对象:面对对象是自底向上抽象的过程
1) 封装:隐藏内部的属性和实现细节,对外仅公开接口;优点:将其隔离;便于使用;提高重用性;安全性。
2) 继承:对父类进行继承和拓展,可以实现单继承和多重继承;优点:提高代码的复用性,同时为多态的产生提供一个前提; 缺点:只可以单继承,多重继承增加了类与类之间的耦合性,不建议继承的深度太深。
3) 多态:父类的引用指向子类的对象,实现的前提重写父类的方法;优点:提高了代码的可拓展性;局限性:只能访问父类的方法,不能访问子类特有的方法,且父类和子类需要满足继承或者实现的关系,注意:只是对方法适用,对成员属性并不适用。
9.重载和重写的区别
重载:是指在方法名相同除去修饰之外的返回值不同或者传入参数的类型或者数量不同的方法的统称,也就是说假如返回值类型相同,参数类型及数量完全一致,方法名相同,那么就是同一个方法;
重写:是指对继承的父类或者实现的接口的方法的重写,重写方法可以添加final ,synchronized来修饰重写的方法,不能用static修饰,被static修饰的方法不能被重写。
10.程序的入口main方法
执行main方法的时会相应的初始化该类及父类
在没有manifest文件或者多个main方法的情况下,指定类运行main方法
java -classpath G:\Javacommand\dollapp.jar hello 备注(G:\Javacommand\dollapp.jar jar的完整的路径 hello 类名)
在存在manifest的情况下,直接可以执行下述命令即可
java -jar <jar-file-name>.jar
manifest的写法可以查看gradle和maven的该文件的写法
11.内部类(除了匿名内部类其他用的并不是很多)
1)内部类的修饰
内部类可以被public/protected/默认/private来修饰以及static修饰及final修饰。
2)内部类的初始化
实例化和局部内部类的初始化需要建立在外部类初始化的前提下,静态内部类可以不初始化外部类(有点类似静态方法的调用),但是需要初始化静态内部类
3) 内部类与外部类的访问
内部类可以对外部类进行访问,外部类不能对内部类直接进行访问,可以通过实例化内部类的方式进行访问,实例内部类中不能有static修饰的成员(因为外部类加载的时候,并不会加载它),局部内部类和实例化内部类相似,不同处是局部内部类类似于局部变量只能在方法的内部中使用,不能被外部使用,而实例化内部类可以被外部间接的使用,内部类可以存在于接口中(存在接口中的类是静态的内部类,没写static及public默认会补全),实例化方法过程类似一般类中的静态内部类
public interface InterfaceTest {
class InnerTest{
public void test () {
System.out.println("innertest");
}
}
}
public class Test extends InterfaceTest.InnerTest{
public static void main(String[] args) {
Test test = new Test();
test.test();
}
}
4) 内部类的继承
内部类是可以继承的,继承实例内部类时,构造方法中的super相应的需要写成外部类.super的方式进行对内部类进行初始化,继承静态内部类的初始化类似一般的继承
public class InnerExtends extends InterfaceStaticInner.cc{
public static void main(String[] args) {
InnerExtends extend = new InnerExtends();
extend.ss();
}
}//ss…
public class Father {
public class test {
public void printTest() {
System.out.println("printtest");
}
}
}
public class Son extends Father.test {
public Son(Father father) {
father.super();
}
public static void main(String[] args) {
}
}
5) 内部类this关键字
内部类的this关键字指的是该类对象。
public class InnerThis {
class Outter {
private int a = 1;
class Inner {
private int a = 2;
public void print() {
int a = 3;
System.out.println("局部变量:" + a);
System.out.println("内部类变量:" + this.a);
System.out.println("外部类变量:" + Outter.this.a);
}
}
}
public static void main(String[] args) {
Outter.Inner inner = new InnerThis().new Outter().new Inner();
inner.print();
}
}//结果 局部变量:3 ,内部类变量:2 ,外部类变量:1
看看下面或许你就明白了
public class ThisTest {
private int i=3;
public void test() {
System.out.println(ThisTest.this.i);
}
public static void main(String[] args) {
new ThisTest().test();
}
}//3
6) 匿名内部类
匿名内部类没有构造方法,但是会调用父类的初始化方法
public class InnerClass {
public void method() {
System.out.println("hehe");
}
public static void main(String[] args) {
new InnerClass() {
@Override
public void method() {
System.out.println("xixi");
}
}.method();
} //xixi
}
注意 :在jdk1.7以前的老版本中如下情况可能出现异常,那么需要将String str用final修饰 ,但是在jdk1.8版本及以上版本测试时不会出现异常
public class InnerClass {
public void method(String str) {
System.out.println("hehe");
}
//局部内部类的问题
public static void main(String[] args) {
String str="ll";
new InnerClass() {
@Override
public void method(String str) {
System.out.println("xixi..."+str);//str出现异常
}
}.method(str);
} //xixi…ll
}
匿名内部类的内部新建方法(不是来自实现,覆盖重写),不能被使用;
public class DeamonInnerTest {
public static void main(String[] args) {
Person person = new Person() {// test方不能被使用
public void test() {// 但是可以用多态的方式去使用,可以是覆盖原方法中方法可以使用
// 也就是在原类里面需要有这个方法,不论是原类自己写的还是还是继承或者实现的,反正要有才能使用
System.out.println(1111);
}
};
class Student {
public void test() {
System.out.println(1111);
}
}
;
Student student = new Student();
student.test();// 1111
}
}
class Person {
public void test() {// 但是可以用多态的方式去使用,不写这个方法 ,上面的person.test是不能被使用的
System.out.println(0000);
}
}