1.static静态变量
- 被static修饰的成员变量,叫做静态变量
特点:被该类所有对象共享;不属于对象属于类;随着类的加载而加载的,优先于对象存在
调用方式:类名调用、对象名调用
- 被static修饰的成员方法,叫做静态方法
特点:多用在测试类和工具中; javabean类中很少会用
调用方式:类名调用;对象名调用
static的注意事项:
静态方法只能访问静态变量和静态方法
非静态方法可以访问静态变量或静态方法,也可以访问非静态的成员变量和非静态的成员方法
静态方法中是没有this关键字
javabean类:用来描述一类事务的类。比如,Student,Teacher,Dog,Cat等。
测试类:用来检查其他类是否书写正确,带有main方法的类,是程序的入口。
工具类:不是用来描述一类事物的,而是帮我们做一些事情的类
main方法:
public:被JVM调用,访问权限足够大;
static:被JVM调用,不用创建对象,直接类名访问;因为main方法是静态的,所以测试类中其他方法也需要是静态的
void:被JVM调用,不需要给JVM返回值
main:一个通用的名称,虽然不是关键字,但是被JVM识别
2.工具类
- 类名见名知意
- 私有化构造方法
- 方法定义为静态
按照以下要求编写一个数组的工具类:ArrayUtil
- 提供一个工具类方法printArr,用于返回整数数组的内容。
返回的字符串格式如:[10,20,50,34,100](只考虑整数数组,且只考虑一堆数组)
- 提供这样一个工具方法getArrage,用于返回平均分(只考虑浮点型数组,且只考虑一堆数组)
- 定义一个测试类TestDemo,调用该工具类的工具方法,并返回结果。
示例代码:
public class TestDemo {public static void main(String args[]){int[] arr1={1,2,3,4,5};String str=ArrayUtil.printArr(arr1);System.out.println(str);double arr[]={2.2,3.4,2.5,6.7};double avg=ArrayUtil.getAverage(arr);System.out.println(avg);} }public class ArrayUtil {private ArrayUtil() {}public static String printArr(int arr[]){StringBuilder sb = new StringBuilder();sb.append("[");for(int i = 0; i < arr.length ; i++){if(i==arr.length-1)sb.append(arr[i]);else sb.append(arr[i]+", ");}sb.append("]");return sb.toString();}public static double getAverage(double[] arr){double sum=0;for(int i = 0; i<arr.length; i++){sum+=arr[i];}return sum/arr.length;} }
3.封装 使用关键字extends
public class Student extends Person{}//Student称为子类(派生类),Person称为父类(基类或超类)
使用继承可以把多个子类中重复的代码抽取到父类中,提高代码的复用性。
子类可以在父类的基础上,增加其他功能,使子类更强大。
特点:Java只支持单继承,不支持多继承,但支持多层继承
单继承:一个子类只能继承一个父类
不支持多继承:子类不能同时继承多个父类
多层继承:子类A继承父类B,父类B可以继承父类C
每一个类都直接或间接的继承于Object
- 构造方法:父类的构造方法不能被子类继承
public class TestDemo {public static void main(String args[]) {Zi z1 = new Zi();//不报错因为类中会自动添加空参构造方法Zi z2 = new Zi("zhangsan",23);//会报错 } }class Fu{String name;int age;public Fu() {}public Fu(String name,int age){this.name=name;this.age=age;}}class Zi extends Fu{}
子类中所有的构造方法默认先访问父类中的无参构造,再执行自己
子类构造方法的第一行语句默认是:super(),不写也存在
- 成员变量:子类能够继承父类的成员变量,但是父类中被private修饰的不能直接使用,需要通过get和set方法使用
访问特点:就近原则,谁离我近我就用谁//先局部再本类,然后父类,逐级向上
System.out.println(name); System.out.println(this.name); System.out.println(super.name);
- 成员方法:只有父类中的虚方法才能被子类继承
(从最顶级的父类开始设计虚方法表,二级父类在顶级的基础上加上自己的虚方法表,在继承关系中顺延)虚方法:非private,非static,非final
访问特点:直接调用满足谁离我近我就用谁;super调用直接访问父类
4.方法的重写(注解@Override):当父类的方法不能满足子类现在的需求时,需要进行方法重写
书写格式:在继承体系中,子类出现和父类一模一样的方法声明,我们就称子类这个方法是重写的方法。方法的重写会覆盖虚方法表中的方法
重写注意事项和要求:
- 重写方法的名称、形参列表必须与父类中的一致。
- 子类重写父类方法时,访问权限子类必须大于等于父类(空着不写<protectes<public)
- 子类重写父类方法时,返回值类型子类必须小于等于父类
- 建议:重写的方法尽量和父类保持一致
- 只有被添加到虚方法表中的方法才能被重写
5.多态 同类型的对象,表现出的不同形态
表现形式: 父类类型 对象名称 = 子类对象;
多态的前提:有继承关系;有父类引用指向子类对象(例如Fu f = new Zi(); );有方法重写
调用成员方法:编译看左边,运行看右边(javac编译代码的时候,会看左边的父类中有没有这个方法,如果有编译成功,反之编译失败。java运行代码的时候,实际上运行的是子类中的方法。)
调用成员变量:编译看左边,运行也看左边
多态的优势:
(1) 在多态形势下,右边对象可以实现解耦合,便于扩展和维护。
Person p = new Student();//当需要时可以改成Teacher(); p.work;//业务逻辑发生改变时,后续代码无需修改
(2)定义方法的时候,使用父类型作为参数,可以接收所有子类对象,体现多态的扩展性与便利。
弊端:
public class TestStudent {public static void main(String[] args){Animal a = new Dog();a.eat();//编译看左边,运行靠右边//多态的弊端:不能调用子类的特有功能//报错原因:调用成员方法时编译看左边,运行看右边//编译的时候检查左边的父类中是否有该方法,没有则直接报错a.lookHome();//报错
//解决方案 变回子类型
//Dog d = (Dog)a;
//d.lookHome();
} }class Animal{public void eat(){System.out.println("动物在吃东西");} } class Dog extends Animal{@Overridepublic void eat(){System.out.println("狗吃骨头");}public void lookHome(){System.out.println("狗看家");} } class Cat extends Animal{@Overridepublic void eat(){System.out.println("猫吃鱼");} }
a instancdof Dog: a是不是Dog类型
新特性为 a instancdof Dog d: 先判断a是否为Dog类型,如果是,则强转成Dog类型,转换之后变量名为d; 如果不是,则不强转,结果直接是false
引用数据类型的类型转换,有几种方式? 自动类型转换,强制类型转换
强制类型转换能解决什么问题?
- 可以转换成真正的子类类型,从而调用子类独有功能。
- 转换类型与真实对象类型不一致会报错。
- 转换的时候用instanceof关键字进行判断
6.包和final
包就是文件夹。用来管理各种不同功能的Java类,方便后期代码维护。
包名的规则:公司域名反写+包的作用,需要全部英文小写,见名知意。
package com.cnblogs.domain.Student;//全类名、全限定名
使用其他类的规则:
使用同一个包中的类时,不需要导包。
使用java.lang包中的类时,不需要导包。
其他情况都需要导包。
如果同时使用两个包中的同名类,需要用全类名(包名+类名)。
- final 是最终的,不可以被改变的。
用final修饰一个方法:表明该方法是最终方法,不能被重写;用final修饰一个类:表明该类是最终类,不能被继承;用final修饰一个变量:叫做常量,只能被赋值一次。
- 常量 命名规范:单个单词全部大写;多个单词:全部大写,单词之间用下划线隔开
注:final修饰的基本变量是基本类型,那么变量存储的数据值不能发生改变; final修饰的变量是引用类型,那么变量存储的地址值不能发生改变,对象内部的可以改变。
- 权限修饰符: 是用来控制一个成员能够被访问的范围的, 可以修饰成员变量,方法,构造方法,内部类。
四种作用范围由小到大:private < 空着不写(default)< protected < public
权限修饰符的使用规则:实际开发中一般只用private和public,成员变量私有,方法公开
特例:如果方法中的代码是抽取其他方法中共性代码,这个方法一般也私有
- 构造代码块:写在成员位置的代码块
作用:可以把多个构造方法中重复的代码抽取出来
执行时机:我们在创造本类对象的时候会先执行构造代码块再执行构造方法
- 静态代码块: 格式:static{}
特点:需要通过static关键字修饰,随着类的加载而加载,并且自动触发,只执行一次
使用场景:在类加载的时候,做一些数据初始化的时候使用
static{System.out.println("静态代码块执行");//只执行一次 }
7.抽象类和抽象方法: 抽象方法子类必须强制重写
抽象方法:将共性的行为(方法)抽取到父类之后。由于每一个子类执行的内容是不一样的,所以,在父类中不能确定具体的方法体。该方法就可以定义为抽象方法。
抽象类:如果一个类中存在抽象方法,那么该类就必须声明为抽象类。
定义示例:
public abstract class Person {//抽象类public abstract void work();//抽象方法 }
注意事项:
(1) 抽象类不能实例化(不能创建对象)
(2) 抽象类中不一定有抽象方法,有抽象方法的类一定是抽象类
(3) 可以有构造方法
(4) 抽象类的子类要么重写抽象类中的所有抽象方法;要么是抽象类
public abstract class Animal {private String name;private int age;public Animal() {}public Animal(String name, int age) {this.name = name;this.age = age;}public void setName(String name) {this.name = name;}public void setAge(int age) {this.age = age;}public String getName() {return name;}public int getAge() {return age;}public void drink(){System.out.println("动物在喝水");}public abstract void eat(); }
public class Frog extends Animal{public Frog() {}public Frog(String name, int age) {super(name, age);}@Overridepublic void eat() {System.out.println("青蛙在吃虫子");} }
8.接口 接口是一种规则,是对行为的抽象
- 接口用关键字interface来定义 public Interface 接口名{}
- 接口不能实例化
- 接口和类之间是实现关系,通过implements关键字表示 public class 类名 implements 接口名{}
- 接口的子类(实现类):要么重写接口中的所由抽象方法,要么是抽象类
- 实现一个接口要重写里面所有的抽象方法
注意1:接口和类的实现关系,可以单实现,也可以多实现。
public class 类名 implements 接口名1,接口名2{}
注意2:实现类还可以在继承一个类的同时实现多个接口。
public class类名extends父类 implements接口名1,接口名2{}
public class Java01 {public static void main(String[] args) {Frog f= new Frog("小青", 1);System.out.println(f.getName()+", "+f.getAge());f.eat();f.swim();Rabbit r = new Rabbit("小白",2);System.out.println(r.getName()+", "+r.getAge());r.eat();} }
ublic abstract class Animal {private String name;private int age;public Animal() {}public Animal(String name, int age) {this.name = name;this.age = age;}public void setName(String name) {this.name = name;}public void setAge(int age) {this.age = age;}public String getName() {return name;}public int getAge() {return age;}public void drink(){System.out.println("动物在喝水");}public abstract void eat(); }
public interface Swim {public abstract void swim(); }
public class Rabbit extends Animal{public Rabbit() {}public Rabbit(String name, int age) {super(name, age);}@Overridepublic void eat() {System.out.println("兔子吃胡萝卜");} }
public class Frog extends Animal implements Swim{public Frog() {}public Frog(String name, int age) {super(name, age);}@Overridepublic void eat() {System.out.println("青蛙在吃虫子");}@Overridepublic void swim() {System.out.println("青蛙在游泳");} }
public class Dog extends Animal implements Swim{public Dog() {}public Dog(String name, int age) {super(name, age);}@Overridepublic void eat() {System.out.println("狗在吃骨头");}@Overridepublic void swim() {System.out.println("狗在游泳");} }
接口中成员的特点:
- 成员变量 只能是常量 默认修饰符:public static final
- 无构造方法
- 成员方法 只能是抽象方法 默认修饰符 public abstract
接口和类之间的关系:
- 类和类的关系:继承关系,只能单继承,不能多继承,但是可以多层继承
- 类和接口的关系:实现关系,可以单实现,也可以多实现,还可以在继承一个类的同时实现多个接口。
- 接口和接口的关系:继承关系,可以单继承,也可以多继承
JDK8后接口新增方法:
(1) 允许在接口中定义默认方法,需要使用关键字default修饰(作用:解决接口升级的问题)
默认方法定义格式:public default 返回值类型 方法名(参数列表){}
范例:public default void show (){}
注意事项:
- 默认方法不是抽象方法,所以不强制被重写。但是如果被重写,重写的时候去掉default关键字。
- public可以省略,default不能省略
- 如果实现了多个接口,多个接口中存在相同名字的默认方法,子类就必须对该方法进行重写。
(2) 允许在接口中定义静态方法,需要用static修饰。
静态方法的定义格式:public static 返回值类型 方法名(参数列表){}
范例:public static void show(){}
注意事项:
- 静态方法只能通过接口名调用,不能通过实现类名或者对象名调用
- public可以省略,static不能省略
JDK9后接口新增方法:
(3) 接口中私有方法的定义格式:
格式1:private 返回值类型 方法名(参数列表){} //为默认方法服务(普通的私有方法)
范例1:private void show(){}
格式2:private static 返回值类型 方法名(参数列表){} //为静态方法服(静态的私有方法)
范例2:private static void method(){}
接口代表规则,是行为的抽象。想要让哪个类拥有一个行为,就让这个类实现对应的接口就可以了。
当一个方法的参数是接口时,可以传递接口所有实现类的对象,这种方式称之为接口多态。
适配器:解决接口与接口实现类之间的矛盾问题
当一个接口中抽象方法过多,但是只需要使用其中一部分的时候就可以适配器设计模式
书写步骤:(1) 编写中间类XXXAdapter实现对应的接口,对接口中的抽象方法进行空实现
(2) 让真正的实现类继承中间类,重写需要用的方法
(3) 避免其他类创建适配器类的对象,中间的适配器类用abstract进行修饰
public interface Inter {public abstract void method1();public abstract void method2();public abstract void method3();public abstract void method4();public abstract void method5(); }
public class InterImpl extends InterAdapter{//需要哪个方法就重写哪个方法 @Overridepublic void method5() {System.out.println("只要用第五个方法");} }
public abstract class InterAdapter implements Inter{//定义为空方法 @Overridepublic void method1() {}@Overridepublic void method2() {}@Overridepublic void method3() {}@Overridepublic void method4() {}@Overridepublic void method5() {} }
9.内部类:成员内部类/ 静态内部类/ 局部内部类/ 匿名内部类
在一个类的里面再定义一个类,里面的类叫内部类
内部类表示的事务是外部类的一部分;内部类单独出现没有任何意义
内部类的访问特点:
- 内部类可以直接访问外部类的成员,包括私有
- 外部类要访问内部类的成员,必须创建对象
//写一个javabean类描述汽车 //属性:汽车品牌、汽车年龄、汽车颜色、发动机品牌、使用年限 public class Car {//外部类 String carName;int carAge;int carColor;class Engine{//内部类(成员内部类) String engineName;int engineAge;} }
成员内部类
获取成员内部类的对象:(1) 在外部类中编写方法,对外提供内部类对象
(2)直接创建格式: 外部类名.内部类名 对象名 = 外部类对象.内部类对象;
示例1:
//方法一 public class Outer{String name;class Inner{} }public class Test{public static void main(String args[]) {Outer.Inner oi = new Outer().new Inner();} }//方法二 public class Outer{String name;private class Inner{} public Inner getInstance(){return new Inner();} }public class Test{public static void main(String args[]) {Outer o = new Outer();o,getInstance();} }
示例2:
public class Outer {private int a = 10;class Inner {private int a = 20;public void show() {int a=30;System.out.println(a);//30System.out.println(this.a);//20System.out.println(Outer.this.a);}} }public class TestDemo {public static void main(String args[]) {Outer.Inner oi = new Outer().new Inner();oi.show();} }
静态内部类(也是成员内部类中的一种)
静态内部类只能访问外部类中的静态变量和静态方法,如果想要访问非静态的需要创建对象。
格式:外部类名.内部类名 对象名 = new 外部类名.内部类名();
调用非静态方法的格式:先创建对象,用对象调用。
调用静态方法的格式:外部类名.内部类名.方法名();
public class TestDemo {public static void main(String args[]) {//创建静态内部类的对象 只要是静态的东西,都可以用类名点直接获取Outer.Inner oi = new Outer.Inner();oi.show();//静态方法 Outer.Inner.show2();} }public class Outer {int a = 10;static int b = 20;static class Inner {public void show() {Outer o =new Outer();System.out.println(o.a);System.out.println(b);}public static void show2() {System.out.println("show2");}} }
局部内部类
- 将内部类定义在方法里面就叫做局部内部类,类似于方法里面的局部变量。
- 外界无法直接使用,需要在方法内部创建对象并使用。
- 该类可以直接访问外部类的成员,也可以访问方法内的局部变量。
public class TestDemo {public static void main(String args[]) {Outer o = new Outer();o.show();} } public class Outer {int b = 20;public void show(){int a = 10;class Inner{//局部内部类 String name;int age;public void method1(){System.out.println(a);System.out.println(b);System.out.println("method1");}public static void method2(){System.out.println("method2");}}Inner i = new Inner();System.out.println(i.name);System.out.println(i.age);i.method1();Inner.method2();} }
匿名内部类:隐藏了名字的内部类,可以写在成员位置,也可以写在局部位置
格式:
new 类名或者接口名(){
重写方法;//包含了继承或实现;方法重写;创建对象(整体就是一个类的子类对象或者接口的实现类对象)
}
使用场景:当方法的参数是接口或者类时,以接口为例,可以传递这个接口的实现类对象。如果实现类只要使用一次,就可以通过匿名内部类简化代码
public class TestDemo {public static void main(String args[]) {new Swim(){ //没有名字的类是大括号部分 括号中是对Swim接口的实现 new创建该类的对象 @Overridepublic void swim() {System.out.println("重写了游泳的方法");}};method(new Animal(){ //没有名字的类是大括号部分 括号中是animal的子类 new创建该类的对象 @Overridepublic void eat() {System.out.println("重写了eat的方法");}});}public static void method(Animal a){//Animal a = 子类对象 多态a.eat();//编译看左边,运行看右边 } }