目录
1.static静态变量
被static修饰的成员变量,叫做静态变量。
特点:被该类所有对象共享;
不属于对象,属于类;
随着类的产生而存在,优先于对象存在;
调用方式:类名调用(推荐);对象名调用。
e.g:
package csdn;
public class Student {
String name;
static String teacher_name;//一个班的学生,共享一个老师
Student(String name){
this.name=name;
}
public void show_info(){
System.out.print("学生:"+name+" ");
System.out.println("老师:"+teacher_name);
}
}
In a word:当一个类的对象需要共享一个成员变量时,可以使用static修饰该变量,使之成为静态变量,供所有对象共享。
2.静态方法和工具类
特点:多用在测试类和工具类,JavaBean很少用到。
调用方式:类名调用(推荐);对象名调用。
PS:工具类是用来帮助做一些事情的类,在这类需要私有化构造方法(外界创建工具类的对象没有意义),方法定义为静态。
e.g:创建数组工具类,加以测试;
package csdn;
public class ArrayUtil {
//私有化构造方法
private ArrayUtil(){
}
//打印工具
public static String PrintArray(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]+"]");
}
}
String s=sb.toString();
return s;
}
//求平均数工具
public static int PrintAverage(int arr[]){
int sum=0;
for(int i=0;i<arr.length;i++){
sum+=arr[i];
}
return sum/arr.length;
}
}
package csdn;
public class ArrayUtilTest {
public static void main(String[] args) {
//方法类无法外界创建对象,直接使用类名调用成员方法。
int arr[]={1,2,3,4,5};
System.out.println(ArrayUtil.PrintArray(arr));//[1,2,3,4,5]
System.out.println(ArrayUtil.PrintAverage(arr));//3
}
}
3.static注意事项
○静态方法只能访问静态变量和静态方法;
○静态方法中没有this关键字。
4.继承
①.关键字extends,可以让一个类和另一个类建立起继承关系。
e.g:
public class Student extends Person{}
Student称子类(派生类),Person称父类(基类)
好处:子类中重复的代码可以提取到父类中,提高代码复用性;
子类可以在父类的基础上增加功能。
package csdn;
public class Person {
private String name;
private int age;
}
class Student extends Person{
public void Study(){
System.out.println("学生学习");
}
}
class Teacher extends Person{
public void Teach(){
System.out.println("老师授课");
}
}
②.继承的特点
Java只支持单继承(一个子类只继承一个父类),不支持多继承,但支持多层继承
(子类A可以继承父类B,父类B可以继承父类C)。
每个类都直接或间接继承于Object(虚拟机自动)。
public class A{}
//其实是
public class A extends Object{}
子类能访问父类的哪些内容:
构造方法 | 非私有 不可继承 | 私有 不可继承 |
成员变量 | 非私有 可继承 | 私有 可继承 |
成员方法 | 非私有 可继承 | 私有 不可继承 |
③.继承中成员变量的访问特点
就近原则,xxx从局部位置开始找,到本类成员位置找,最后到父类成员位置找。
this.xxx从本类成员位置开始找,到父类成员位置找。
super.xxx直接到父类成员位置找。
public class Test {
public static void main(String[] args) {
Er e=new Er();
e.Print();
}
}
class Die{
String name="爹";
}
class Er extends Die{
String name="儿子";
public void Print(){
String name="儿中儿";
System.out.println(name);//儿中儿
System.out.println(this.name);//儿子
System.out.println(super.name);//爹
}
}
④.继承中成员方法的访问特点
方法重写:当父类中的方法不满足子类的要求,就需要重写方法;@Override放在重写方法上面,校验子类重写方法语法;
public class Test02 {
public static void main(String[] args) {
exchangeStudents es=new exchangeStudents();
es.show_me();
}
}
class Students{
public void eat(){
System.out.println("吃河道果实");
}
public void drink() {
System.out.println("喝腐败药水");
}
}
class exchangeStudents extends Students{
public void show_me(){
this.eat();//吃探照果实
this.drink();//喝复用型药水
super.eat();//吃河道果实
super.drink();//喝腐败药水
}
@Override
public void eat(){
System.out.println("吃探照果实");
}
public void drink(){
System.out.println("喝复用型药水");
}
}
方法重写注意事项:
重写的方法名,形参列表要和父类一样;
重写的方法访问权限子类必须大于等于父类(不设权限<protected<public);
重写方法的返回值子类必须小于等于父类;
私有方法不能重写;
静态方法不能重写;
(未添加到虚方法表的方法不能重写);
(重写的本质:覆盖虚方法表中的方法)。
⑤.继承中构造方法的访问特点
父类的构造方法不会被子类继承;子类的所有构造方法默认先访问父类的无参构造,再执行自己。
子类的构造方法第一句默认super();不写也存在且必须在第一行。
子类想调用父类的有参构造时必须加super。
e.g:
public class Test {
public static void main(String[] args) {
Students s=new Students("王德发",19);
s.Print();
}
}
class Person {
String name;
int age;
public Person(){
System.out.println("父类的无参构造");
}
public Person(String name,int age){
this.name=name;
this.age=age;
}
}
class Students extends Person{
public Students(){
super();
System.out.println("子类的无参构造");
}
public Students(String name,int age){
super(name,age);
}
public void Print(){
System.out.println(this.name);
System.out.println(this.age);
}
}
5.多态
①.多态就是对象的多种形态
前提:有继承关系/实现关系
有父类引用指向子类对象
有方法的重写
好处:使用父类对象为参数,可以接收所有子类对象。
public class Test {
public static void main(String[] args) {
Student s=new Student();
s.setName("王德发");
s.setAge(19);
Teacher t=new Teacher();
t.setName("墨菲特");
t.setAge(20);
show(s);//学生叫:王德发年龄19
show(t);//老师叫:墨菲特年龄20
}
//父类对象作参数
public static void show(Person p){
p.Print();
}
}
class Person {
String name;
int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public void Print(){
System.out.println(this.name+" "+this.age);
}
}
class Student extends Person{
@Override
public void Print(){
System.out.println("学生叫:"+this.name+"年龄"+this.age);
}
}
class Teacher extends Person{
@Override
public void Print(){
System.out.println("老师叫:"+this.name+"年龄"+this.age);
}
}
②.
调用成员变量时:编译看左边(父类),运行看左边(子类);
调用成员方法时:编译看左边,运行看右边;
public class Test {
public static void main(String[] args) {
//左 右
Animal a=new Dog();
//调用成员变量,javac编译时看左边,如果左边(父类)有该变量,编译成功,反之编译失败
//javac运行时看左边,实际获取的就是父类中该成员变量的值。
System.out.println(a.name);//动物
//调用成员方法,javac编译时看左边,如果左边(父类)有该方法,编译成功,反之编译失败
//javac运行时看右边,实际获取的是子类中的成员方法
a.Print();//这是个狗
}
}
class Animal{
String name="动物";
public void Print(){
System.out.println("这是个动物");
}
}
class Dog extends Animal{
String name="狗";
@Override
public void Print(){
System.out.println("这是个狗");
}
}
③多态的优势和缺陷
优势:定义方法时,使用父类作参数,可以接收所有子类,便利;
在多态形式下,子类可以实现解耦合,便于维护。
弊端:不能使用子类独有的功能。
解决方案:转换成子类类型,从而调用子类独有的功能。
public class Test {
public static void main(String[] args) {
Animal a=new Dog();
//a.EatRou();报错
//原因:多态情况下调用成员方法,从左边找,父类中未定义Eat函数,故javac编译报错
//解决:类型转换:
Dog d = (Dog)a;
d.EatRou();
}
}
class Animal{
public void Print(){
System.out.println("动物吃饭");
}
}
class Dog extends Animal{
public void EatRou(){
System.out.println("狗吃小肉干");
}
}
class Cat extends Animal{
public void EatYu(){
System.out.println("猫吃小鱼干");
}
}
PS:instanceof关键字 a instance typeB:判断a是否为B类型,是返回true否返回false。
有时为了避免类型转换出错,会使用instanceof先判断再进行强转。
6.包
包就是文件夹,用来管理不同功能的Java类。
导包规则:
使用同一包中的类,不需要导包;
使用java.lang包中的类(如String),不需要导包;
使用两个包中的同名类,需要使用全类名。
7.final关键字
修饰方法时:表示不能被重写;
修饰类时:表示不能被继承;
修饰变量时:表示常量,只能被赋值一次。
常量命名规范:单个单词:全部大写;多个单词:全部大写,用下划线隔开。
细节:final修饰基本数据类型(如:int),表示数据值不能改变;
final修饰引用数据类型(如:数组),表示数据地址值不能改变,但存储的数值可以改变。
8.权限修饰符
范围:private<默认<protected<public
同一类中 | 同一个包中其他类 | 不同包下的子类 | 不同包下的无关类 | |
private | √ | |||
默认 | √ | √ | ||
protected | √ | √ | √ | |
public | √ | √ | √ | √ |
实际开发中使用频繁的是private和public
9.代码块
①局部代码块
public class Code {
public static void main(String[] args) {
{
int a=10;
}//在这里a已经从内存中消失
System.out.println(a);//a的生命周期已结束,无法访问
}
}
是为了节省内存,提前结束变量生命周期。
现在已经用不到,计算机内存不需要节省那么点空间。
②构造代码块
写在成员位置,把多个构造方法重复的代码提取出来,优先于构造方法执行。
public class Code {
public static void main(String[] args) {
Students s=new Students();
//这是构造代码块
//空参构造
Students s_1=new Students("王德发",19);
//这是构造代码块
//有参构造
}
}
class Students{
String name;
int age;
{
System.out.println("这是构造代码块");
}
public Students() {
System.out.println("空参构造");
}
public Students(String name, int age) {
System.out.println("有参构造");
this.name = name;
this.age = age;
}
}
这种方法现在也不常用,因为不灵活,构造代码块必定执行,且优先于构造方法执行。
更常用将多个构造方法中的重复代码提取成一个方法。
③静态代码块
static{}
特点:随着类的加载而执行,且只执行一次。用于加载类时的初始化。
public class Code {
public static void main(String[] args) {
Students s=new Students();
//这是构造代码块
//空参构造
Students s_1=new Students("王德发",19);
//有参构造
}
}
class Students{
String name;
int age;
static {
System.out.println("这是构造代码块");
}
public Students() {
System.out.println("空参构造");
}
public Students(String name, int age) {
System.out.println("有参构造");
this.name = name;
this.age = age;
}
}
10.抽象类和抽象方法
将共性的方法抽取到父类后,如果不能确定具体的方法体,就可以定义为抽象方法;
如果一个类中存在抽象方法,这个类必须声明为抽象类。
定义格式:
抽象方法:public abstract 返回值类型 方法名(参数列表);
抽象类:public abstract class 类名{}
public abstract class Abstract {
public abstract void Work();
}
注意事项:Ⅰ抽象类不能实例化(创造对象);
Ⅱ抽象类中不一定有抽象方法,有抽象方法的一定是抽象类;
abstract class Animals{
public void Print(){
System.out.println("动物");
}
}
Ⅲ可以有构造方法;
Ⅳ抽象类的子类要么重写抽象类所有抽象方法,要么该子类也是抽象类。
11.接口
①接口就是一种对行为的抽象。
接口用关键字interface定义
public interface 接口名{}
接口不能实例化
接口和类之间是实现关系,用关键字implements实现
public class 类名 implements 接口名{}
接口的子类(实现类)要么重写接口的所有抽象方法,要么该子类是抽象类
接口的子类可以多实现
public class 类名 implements 接口1,接口2{}
还可以在继承父类的同时实现多个接口
public class 子类名 extends 父类名 implements 接口1,接口2{}
e.g:创建Person类,子类为中国人,外国人,假人;
因为假人没有Speak行为,故Speak行为需写成接口,供中国人和外国人调用。
public class Test {
public static void main(String[] args) {
Chinese c=new Chinese("王德发",19);
System.out.println("名字:"+c.getName()+"年龄:"+c.getAge());
c.speak();
c.food();
dummy d=new dummy("目标假人",190);
System.out.println("名字:"+d.getName()+"年龄:"+d.getAge());
d.food();
}
}
abstract class Person {
private String name;
private int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public abstract void food();
}
interface Speak {
public abstract void speak();
}
class Chinese extends Person implements Speak{
public Chinese() {
}
public Chinese(String name,int age) {
super(name,age);
}
@Override
public void food() {
System.out.println("吃饺子");
}
@Override
public void speak() {
System.out.println("讲汉语");
}
}
class foreigners extends Person implements Speak{
public foreigners(){
}
public foreigners(String name,int age){
super(name,age);
}
@Override
public void food() {
System.out.println("吃比萨");
}
@Override
public void speak() {
System.out.println("讲外语");
}
}
class dummy extends Person{
public dummy(){
}
public dummy(String name,int age){
super(name,age);
}
@Override
public void food() {
System.out.println("吃伤害");
}
//假人没有Speak行为
}
②接口中成员特点
成员变量只能是常量,默认 public static final
没有构造方法
成员方法只能是抽象方法,默认public abstract
③JDK8接口中新增的方法
JDK7之前接口中只能写抽象方法;
JDK8可以定义有方法体的方法;
JDK9可以定义私有方法。
默认方法:public default 返回值类型 方法名(){}
注意:默认方法不是抽象类,不强制重写。如果要重写,重写时去掉default;
public可以省略,default不能省略;
静态方法:public static 返回值类型 方法名(){}
注意:静态方法只能用接口名调用;
public可以省略,static不能省略。
④接口应用:
接口代表规则,是行为的抽象。想让哪个类拥有这个行为,就让这个类实现对应的接口;
当一个方法的参数是接口,可以传递所有接口的实现类,这种方式称为接口的多态。
⑤适配器设计模式
当一个接口中抽象方法过多,而我们只需要用到一部分,就可以使用适配器设计模式;
书写步骤:
编写中间类XXXAdapter实现对应接口,对接口中的抽象方法全部进行空实现,让真正的实现类继承中间类,重写需要的方法,为了避免其他类创造中间类的对象,中间适配器类需要用abstract修饰。
12.内部类
①内部类表示的事物是外部类的一部分,内部类单独出现没有意义。
内部类可以直接访问外部类的成员,包括private修饰的;
外部类不能直接访问内部类的成员,如果想访问,必须创建对象。
e.g:引擎和汽车的关系
public class Car {
String name;
int age;
String brand;
public void show(Car this){
System.out.println("车辆年限:"+this.age);
Engine e=new Engine();//外部类想访问内部类成员,需要创建对象
System.out.println("引擎寿命:"+e.engineage);
}
class Engine{
String enginename;
int engineage;
public void show(){
System.out.println("车辆品牌:"+brand);
System.out.println("引擎型号:"+enginename);
}
}
}
②内部类的分类
成员内部类:写在成员位置,属于外部类的成员
获取内部类成员的方法:
Ⅰ.在外部类编写对外提供内部类成员的方法
Ⅱ.外部类名.内部类名 对象名 = new 外部类名().new 内部类名();
public class Test {
public static void main(String[] args) {
Outer.Iner oi=new Outer().new Iner();
oi.show();//10
}
}
class Outer{
int a=10;
class Iner{
public void show(){
System.out.println(a);
}
}
}
外部类成员变量和内部类成员变量重名时,怎么在内部类访问
class Outer{
private int a=10;
class Iner{
private int a=20;
public void show(){
int a=30;
System.out.println(a);//30
System.out.println(this.a);//20
System.out.println(Outer.this.a);//10
}
}
}
局部内部类
将内部类定义在方法里就叫局部内部类。
外部无法直接使用,要在方法内创建对象方可使用
局部内部类可以直接访问外部类的成员,也可访问方法内的局部变量
静态内部类
当成员内部类用static修饰时,就叫静态内部类,静态内部类只能访问外部类的静态成员变量和静态成员方法,如果想访问非静态的需要创建对象。
创建静态内部类对象:外部类名.内部类名 对象名=new 外部类名.内部类名();
调用静态方法:外部类名.内部类名.方法名();
public class Test {
public static void main(String[] args) {
Outer.Iner oi=new Outer.Iner();
oi.show1();//静态内部类的非静态方法
Outer.Iner.show2();//静态内部类的静态方法
}
}
class Outer{
static class Iner{
public void show1(){
System.out.println("静态内部类的非静态方法");
}
public static void show2(){
System.out.println("静态内部类的静态方法");
}
}
}
匿名内部类
匿名内部类本质就是隐藏了类名的内部类
格式:new 类名/接口名(){
重写方法;
};
绿色的部分其实才是匿名内部类,加上new 类名/接口名后他的本质应该是一个对象,和类名/接口名的关系应该是继承/实现。
e.g:直接将匿名内部类作为对象传给方法。
public class Test {
public static void main(String[] args) {
show(
new Animal(){
@Override
public void eat(){
System.out.println("狗吃骨头");
}
}
);//狗吃骨头
}
public static void show(Animal a){
a.eat();
}
}
abstract class Animal{
public abstract void eat();
}
In a word,匿名内部类整体是一个类的对象或者一个接口的实现类对象。
使用场景:
当方法的参数是类/接口时,可以传递这个类的子类对象/实现类对象,如果只需要执行一次,就可以使用匿名内部类简化代码。