类(设计图):是对象共同特征的描述;
对象:是真实存在的具体事物。
在Java中,必须先设计类,才能获得对象。
类的定义格式:
public class 类名{
1、成员变量(代表属性,一般是名词)
2、成员方法(代表行为,一般是动词)
3、构造方法
4、代码块
5、内部类
}
例:
public class Phone{
//属性(成员变量)
String brand;
double price;
//行为(成员方法)
public void call(){
}
public void playGame(){
}
}
类的对象创建格式
类名 对象名 = new 类名();
例:
Phone p = new Phone();
对象的使用格式:
- 访问属性:对象名.成员变量
- 访问行为:对象名.方法名(...)
在Javabean类中,是不写main方法的。
我们可以在测试类中创建javabean类的对象并进行赋值调用。
权限修饰符是用来控制一个成员能够被访问的范围的。可以修饰成员变量,方法,构造方法,内部类。
有四种作用范围由小到大(private<空着不写(缺省/默认)<protected<public)
修饰符 | 同一个类中 | 同一个包中 其他类 |
不同包下的子类 | 不同包下的其他类 |
private | √ | |||
空着不写 | √ | √ | ||
protected | √ | √ | √ | |
public | √ | √ | √ | √ |
实际开发中,一般值用private和public
特例:一个方法被其他多个方法调用,那么这个方法一般也私有。
区别 | 成员变量 | 局部变量 |
类中位置不同 | 类中,方法外 | 方法内,方法申明上 |
初始化值不同 | 有默认初始化值 | 没有,使用之前需要赋值 |
内存位置不同 | 堆内存 | 栈内存 |
生命周期不同 | 随着对象的创建而存在,随着对象的消失而消失 | 随着方法的调用而存在,随着方法的运行结束而消失 |
作用域 | 整个类中有效 | 当前方法中有效 |
public class people{
private int age;//成员变量
public void method(){
int age = 10;//局部变量
System.out.println(age);
}
}
Java中代码执行过程中调用变量将遵守就近原则,即执行某语句时,该语句中含有变量,若存在同名的变量,则该语句会调用离他最近的变量。如上面代码所示,输出语句中的age,所带入的时局部变量的age。
this关键字的作用:可以区分成员变量和局部变量,可避免就近原则
public class people{
private int age;//成员变量
public void method(){
int age = 10;//局部变量
System.out.println(this.age);
}
}
如上代码,此时,输出语句中的age便是调用成员变量的age。
this的本质:代表方法调用者的地址值
super:代表父类的存储空间。
static表示静态,是Java中的一个修饰符,可以修饰成员方法,成员变量
被static修饰的成员变量,叫作静态变量
特点:
调用方式:
静态变量存储在静态储存位置(静态区位于堆内存中)。
被static修饰的成员方法,叫做静态方法
特点:
调用方式:
static的注意事项
final关键字可以修饰方法,类及变量,情况如下
final修饰方法:
表明该方法是最终方法,不能被重写。
final修饰类:
表明该类是最终类,不能被继承。
final修饰变量:
表明该变量是常量,只能赋值一次,并且定义时必须赋值。
实际开发中,常量一般作为系统的配置信息,方便维护,提高可读性。
常量的命名规范:
细节:
final修饰的变量是基本类型:那么变量存储的数据值不能发生改变。
final修饰的变量是引用类型:那么变量存储的地址值不能发生改变,对象内部所存储的信息可以改变。
构造方法也叫作构造器、构造函数。
作用:在创建对象的时候给成员变量进行赋值的。
构造方法的格式:
public class Student{
修饰符 类名(参数){
方法体;
}
}
注意点:
执行时机:
例:
public class Person{
private String name;
private int age;
public Person(){
......
}//空参构造
public Person(String name,int age){
......
}//带参构造
}
注意事项:
推荐使用方式:无论是否使用,都手动书写无参数构造方法,和带全部参数的构造方法。
用来描述一类事物的类
①类名需要见名知意
②成员变量使用private修饰
③提供至少两个构造方法
④成员方法
用来检查其他类是否书写正确,带有main方法的类。
不是用来描述一类事物的,而是帮我们做一些事情的类。
①类名需要见名知意
②私有化构造方法
目的:为了不让外界创建他的对象。其对象无实际意义
③方法定义为静态
方便调用,通过类名进行调用。
写在成员位置的代码块。
作用:可以把多个构造方法中重复的代码抽取出来。
执行时机:我们在创建本类对象的时候会先执行构造代码块在执行构造方法。
格式:static{}
特点:需要通过static关键字修饰,随着类的加载而加载,并且自动触发,只执行一次
使用场景:在类加载的时候,做一些数据初始化的时候去使用
封装:对象代表什么,就得封装相应的数据,并提供数据对应的行为。
继承:继承是面向对象三大特征之一,可以让类跟类之间产生父子的关系。
继承格式:
public class 子类 extends 父类{}
Java中提供一个关键字extends,用这个关键字,我们可以让一个和另一类建立起继承关系。
public class Student extends Person{}
Student称为子类(派生类),Person称为父类(基类或超类)。
使用继承的好处:
Java只支持单继承,不支持多继承,但支持多层继承。单继承:一个子类只能继承一个父类。不吃成多继承:子类不能同时继承多个父类。多层继承:子类A继承父类B,父类B可以继承父类C,其中B为A的直接父类,C为A的间接父类。每一个类都直接或者间接地继承于Object,即如果一个类没有继承任何类,则JVM会默认其继承Object。
子类只能访问父类中非私有的成员。
子类能从父类中继承的内容:
1、构造方法均不能继承
父类的构造方法不能被子类继承,因为父类的构造方法的方法名与子类的类名不同,故不能继承。
2、成员变量都能继承
成员变量无论是否有Private修饰,该变量都能继承;但是,被Private修饰的变量无法进行调用。
3、成员方法,非私有的可以继承,私有的不能继承
只有父类中的虚方法(非private、非static、非final修饰的方法为虚方法)才能被子类继承;父类会将自身的虚方法建成一张虚方法表,并把虚方法表交给子类。
继承中成员变量访问特点:就近原则。
先在局部位置找,本类成员位置找,父类成员位置找,逐级往上。
重名变量情况
System.out.println(name);//从局部位置开始往上找
System.out.println(this.name);//从本类成员位置开始往上找
System.out.println(super.name);//从父类成员位置开始往上找
父类中的构造方法不会被子类继承。
子类中所有的构造方法默认先访问父类中的无参构造,再执行自己。原因是:(1)子类在初始化的时候,有可能会使用到父类中的数据,如果父类没有完成初始化,子类将无法使用父类的数据;(2)子类初始化之前,一定调用父类构造方法先完成父类数据空间的初始化。子类构造方法的第一行语句默认都是:super(),不写也存在即JVM默认会有,且必在第一行;若想调用父类有参构造,必须手动写super进行调用。
当父类的方法不能满足子类现在的需求时,需要进行方法重写。
书写格式:
在继承体系中,子类出现了和父类一模一样的方法声明,我们就称子类这个方法时重写的方法。
@Override重写注解
方法重写的本质是:子类在继承父类的虚方法表示,若出现了方法重写的情况,则该子类的虚方法表会将自己重写的方法覆盖继承下来的被重写的方法。
方法重写的注意事项和要求:
多态:同类型的对象,表现出的不同形态。
多态的表达方式:
父类类型 对象名称 = new 子类类型();
例.
父类与子类的代码:
public class Animals {
String name;
int number;
public Animals(){
}
public Animals(String name,int number){
this.name = name;
this.number = number;
}
public void eat(){
System.out.println("吃饭");
}
}
public class Cat extends Animals{
@Override
public void eat() {
System.out.println("吃鱼");
}
}
public class Dog extends Animals{
@Override
public void eat() {
System.out.println("吃骨头");
}
}
主函数代码:
public class test {
public static void main(String[] args){
Animals animals = new Animals();
Animals dog = new Dog();
Animals cat = new Cat();
as(animals);
as(dog);
as(cat);
}
public static void as(Animals a){
a.eat();
}
}
结果如下:
Person p = new Student();
p.work();//业务逻辑发生变化时,后续代码无需修改
即当不需要学生对象而是老师对象时,可以通过只修改此处的构造方法,而之后的代码都不需要修改。
不能调用子类的特有功能,即调用方法时,编译看左边,运行看右边,那么在编译的时候会先检查左边的父类中有没有这个方法,如果没有则会直接报错。
解决方案:通过强制转换将对象由父类类型变为子类类型
父类类型 对象名 = new 子类类型();//多态创建对象
子类类型 对象名 = (子类类型) 对象名;//将该对象强制转换为子类类型。
tips:强制转换时不能随意转换,转换后的子类类型应与new时的子类类型相同才能转换成功,若转换的为其他子类类型,则会出现报错。
instanceof关键字可以用于判断创建的对象是哪种创建的子类类型,用法为:对象名 instanceof 子类类型;
“对象名 instanceof 子类类型 转换后的对象名”,这种用法为JDK14所新加的特性,可以先判断该对象是否为该子类类型,如果是,则强转成功,转换之后变量名改变,如果不是,则强转失败,结果为false。
包就是文件夹,用来管理各种不同功能的Java类,方便后期代码维护。
全类名(全限定名):包名+类名,用import关键字导入包时用到,特殊情况下需要用其创建对象。
抽象方法:将共性的(即相同的)行为(方法)抽取到父类之后。由于每一个子类执行的内容是不一样的,所以,在父类中不能确定具体的方法体。该方法就可以定义为抽象方法。
抽象类:如果一个类中存在抽象方法,那么该类就必须声明为抽象类。
抽象方法的定义格式:
public abstract 返回值类型 方法名(参数列表);
抽象类的定义格式:
public abstract class 类名{}
抽象类不能实例化,即抽象类不能创建对象。
抽象类中不一定有抽象方法,有抽象方法的类一定是抽象类。
可以有构造方法,当创建子类对象的时候,给属性进行赋值。
抽象类的子类,要么重写抽象类中的所有抽象方法,要么是抽象类(这种情况一般不可取)。
抽象类和抽象方法的意义
防止子类中重写同类行为(同名方法)的结构过于多样化,通过抽象类可以强制子类必须按照某种格式进行重写。
接口的作用是通过接口可以实现不相关类的相同行为,而不需要了解对象所对应的类。即接口更一种规则,是对行为的抽象。
接口用关键字interface来定义
public interface 接口名{}
接口不能实例化
接口和类之间是实现关系,通过implements关键字表示
public class 类名 implements 接口名{}
接口的子类(实现类)要么重写接口中的所有抽象方法,要么是抽象类。
接口和类的实现关系,可以单实现,也可以多实现。
public class 类名 implements 接口名1,接口名2{}
实现类还可以在继承一个类的同时实现多个接口。
public class 类名 extends 父类 implements 接口名1,接口名2{}
允许在接口中定义默认方法,需要使用关键字default修饰,作用:解决接口升级的问题。
接口中默认方法的定义格式:
格式:public default 放回值类型 方法名(参数列表){ }
范例:public default void show(){ }
接口中默认方法的注意事项:
默认方法不是抽象方法,所以不强制重写。但是如果被重写,重写的时候需要去掉default关键字。
public是默认修饰符,可以省略,但default不能省略。若省略,则会被识别为是一个抽象方法。
如果实现了多个接口,多个接口中存在相同名字的默认方法,子类就必须对该方法进行重写。
允许在接口中定义静态方法,需要用static修饰。
接口中静态方法的定义格式:
格式:public static 放回值类型 方法名(参数列表){ }
范例:public static void show() { }
接口中静态方法的注意事项:
静态方法只能通过接口名调用,不能通过实现类名或者对象名调用。
public可以省略,static不能省略。若省略,则会被识别为是一个抽象方法。
接口中私有方法的定义格式:
格式1:private 放回值类型 方法名(参数列表){ }
范例1:private void show(){ }
//该方法一般由默认方法调用
格式2:private static 返回值类型 方法名(参数列表){ }
范例2:private static void show(){ }
//该方法一般由静态方法调用
私有方法的意义在于防止接口外的类调用。
1、接口代表规则,是行为的抽象。想让哪个类拥有一个行为,就让这个类实现对应的接口就可以了。
2、当一个方法的参数是接口时,可以传递接口所有实现类的对象,这种方式称之为接口多态。
设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性、程序的重用性。即设计模式就是各种套路。
适配器设计模式:解决接口与接口实现类之间的矛盾问题。
当一个接口中抽象方法过多,但是我只要使用其中一部分的时候,就可以使用适配器设计模式
实现方式:
编写中间类xxxAdapter,实现对应的接口
对接口中的抽象方法进行空实现,即重写方法体为空
让真正的实现类继承中间类,并重写需要用的方法
为了避免其他类创建适配器类的对象,中间的适配器类用abstract进行修饰
写在一个类里面的类就叫做内部类。
在一个类A的里面,再定义一个类B,类B就是内部类,类A是外部类,除A、B两个类的类称为外部其他类。
内部类表示的事物是外部类的一部分,并且内部类单独出现没有任何意义
内部类可以直接访问外部类的成员,包括私有。
外部类要访问内部类的成员,必须创建对象。
写在成员位置的,属于外部类的成员。
成员内部类可以被一些修饰符所修饰,比如:private,默认,protected,public,static等。
在成员内部类里面,JDK16之前不能定义静态变量,JDK16开始才能定义静态变量。
方式一:
在外部类中编写方法,对外提供内部类的对象
范例:public class Outer{
String name;
class Inner{ }
public Inner getInstance(){
return new Inner()
}
}
之后通过创建一个Outer类的对象,然后用该对象调用方法即可获得内部类的对象。
方式二:
直接创建格式:外部类名.内部类名 对象名 = 外部类对象.内部类对象;
范例:Outer.Inner oi = new Outer().new Inner();
格式:外部类名.this.成员变量名
范例:
public class Outer{
private int a = 10;
class Inner{
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);//30
}
}
}//Outer.this获取了外部类(Outer)的地址值
静态内部类也是成员内部类中的一种。
静态内部类只能访问外部类中的静态变量和静态方法,如果想要访问非静态的需要创建外部类的对象。
创建静态内部类对象的格式:外部类名.内部类名 对象名 = new 外部类名.内部类名();
范例:Outer.Inner oi = new Outer.Inner();
由于有static关键字修饰,故不需要外部类对象,只需要外部类类名即可。
调用非静态方法的格式:先创建对象,用对象调用
调用静态方法的格式:外部类名.内部类名.方法名();
将内部类定义在方法里面就叫做局部内部类,类似于方法里面的局部变量。
外界是无法直接使用局部内部类,需要在方法内部创建对象并使用。
该类可以直接访问外部类的成员,也可以访问方法内的局部变量。
匿名内部类就是隐藏了名字的内部类,可以写在成员位置,也可以现在局部位置。
格式:
new 类名或接口名(){
重写方法;
}
其中实际上包含了继承或实现、方法重写、创建对象。
整体就是一个类的子类对象或者接口的实现类对象。
使用场景
当方法的参数是接口或者类时,以接口为例,可以传递这个接口的实现类对象,如果实现类只要使用一次,就可以用匿名内部类简化代码,不用再定义一个新的实现类了。