代码体现
//定义类的格式
public class 类名 {
//可编写属性
数据类型 变量名1;
数据类型 变量名2;
//可编写方法
修饰符 返回值类型 方法名(参数) {
执行语句;
}
}
类的真正意义就是在描述事物。属性和功能统称为事物中的成员。
事物的成员分为两种:成员属性和成员功能。
成员属性===>成员变量(类中方法外)。
成员功能===>成员方法。
//创建对象的一般格式
类名 引用变量名 = new 类型();
成员变量使用:
赋值格式:引用变量名.成员变量名 = 值;
取值格式:引用变量名.成员变量名
成员方法使用格式:
引用变量名.方法名(值1,值2,...);
局部变量和成员变量
区别一:定义的位置不同
定义在类中的方法外的变量是成员变量
定义在方法中或者方法的{}内语句里面的变量是局部变量
区别二:在内存中的位置不同
成员变量存储在堆中
局部变量存储在栈中
区别三:生命周期不同(皮之不存毛将焉附)
成员变量随着对象的出现而出现在堆中,随着对象的消失而从堆中消失
(成员变量和对象同生共死)
局部变量随着方法的运行而出现在栈中,随着方法的弹栈而消失
(局部变量和方法同生共死)
区别四:有没有默认值
成员变量因为在堆内存中,所有默认的初始化值,默认值和数组的默认值类似
局部变量没有默认的初始化值,必须手动的给其赋值才可以使用。
关键字private
private关键字,也是一个修饰符。可以将属性或者行为私有起来,无法访问。对外提供可访问的方法,让其他程序访问这些方法。同时在方法中可以对数据进行验证。
一般对成员属性的访问动作:赋值(设置set),取值(获取get),因此对私有的变量访问的方式可以提供对应的setXxxx或者getXxxx的方法。
/*
* 人类:
* 属性:姓名,年龄
* 行为:吃饭
*
* 使用关键字private:私有
* 当私有化变量后,变量不能在类外直接访问
* 如果用private修饰成员方法,这个成员方法不能在类外使用
*/
public class Person {
//属性===》成员变量
String name;
private int age;
//我们专门提供一个public修饰的setXxxx
//这个方法的作用就是为属性设置值
public void setAge(int a) {
//正因为有了方法,我们可以在方法中对年龄的值控制
if (a < 0) {
System.out.println("年龄不能指定负值");
return;//直接终止方法
}
age = a;
}
//我们专门提供一个public修饰的getXxxx
//这个方法的作用就是为了获取属性的值
public int getAge() {
return age;
}
}
public class PersonDemo {
public static void main(String[] args) {
Person person = new Person();//默认值:name=null;age=0
//设置成员变量的name和age
person.setName("三丰");
person.setAge(100);
//获取成员变量的name和age
System.out.println(person.getName + " " + person.getAge());
}
}
总结:
类中不需要对外提供的内容都私有化,包括属性和方法。
以后再描述事物,属性都私有化,并提供setXxxx和getXxxx方法对其进行访问。
注意:
私有仅仅是封装的体现形式而已。
关键字this
当方法中出现局部变量和成员变量同名的时候,需要在成员变量名前面加上this来区分成员变量和局部变量。
/*
* 利用getXxxx以及setXxxx来为Person类中的属性设置值和取值
* 当成员变量名和局部变量重名的时候,我们可以利用this关键字来区分
*/
public class Person {
private String name;
private int age;
/*setName和getName*/
/*
*
* 为了让形参名更加见名知意,我们不使用n变量名作为方法形参,我们就用name
*/
public void setName(String name) {
this.name = name;//this.name会使用成员变量
}
public String getName() {
return name;
}
/*setAge和getAge*/
public void setAge(int age) {
this.age = age;//this.age会使用成员变量
}
public int getAge() {
return age;
}
}
public class PersonDemo {
public static void main(String[] args) {
method01();
}
private static void method01() {
Person person = new Person();
//设置成员变量的name和age
person.setName("三丰");
person.setAge(100);
//获取成员变量的name和age
System.out.println(person.getName() + person.getAge());
}
}
继承
1.在Java中,类只支持单继承,不允许多继承。也就是一个类只能有一个直接父类。
2.多个类可以继承一个父类。
3.在Java中,可以多层继承,即一个类的父类可以再去继承另一个父类。
class A {}
class B {}
class C extends A,B {} //语法错误,且不可以同时继承
子父类中成员变量的特点
父类的成员变量是非私有的,子类可以直接访问,若父类成员变量是私有的,则不能直接访问。
当子父类中出现多个同名变量,在子类若要访问父类中的同名变量,必须使用关键字super来完成。super关键字可以用来访问父类的非私有的成员。
成员变量和方法的访问特点
遵循就近原则。在访问成员变量或方法的时候,如果本类有该成员变量或该方法,直接使用,如果没有,继续查找父类。如果所有类都没有则报错。
子类(本类) =》 父类 =》 父类的父类 =》 Object
可以通过关键字super来调用父类的成员方法。
//子类中,访问父类中的成员方法格式:
super.父类中的成员方法();
方法重写
方法重写的必要条件:
1.必须有继承关系,重写针对的是子类的方法重写父类的方法。
2.子类的方法与被重写的父类的方法要保持一致(返回值类型,方法名,形参列表保持一致)。
3.子类的方法的权限 >=父类被重写的方法的权限。
public 默认 protected private
private修饰的方法不被重写,一旦修饰父类的方法,只能父类自己使用,子类根本获取不到。
@override
强制子类的方法重写父类的方法,如果不重写就报错。
public class Demo {}
class A {
public void method(){}
}
class B extends A {
@Override //强制重写
public void method(){}
}
方法重写和方法重载的区别
//方法重载
public void show(int i) {
}
public void show(double j) {
}
//方法重写
public void method(double j) {
}
public void method(double j) {
}
1.权限修饰符
重载:对修饰符没有要求
重写:子类的方法的权限 >= 被重写的父类的方法权限
2.返回值类型
重载:对返回值类型没有要求
重写:子类的方法的返回值类型和父类的方法的返回值类型保持一致
3.方法名
重载:重载的两个方法的方法名保持一致
重写:重写要求子类的方法名和被重写的父类的方法名保持一致
4.形参列表
重载:重载要求两个方法的形参列表不一致(形参个数,形参类型,形参类型顺序)
重写:子类的形参列表和被重写的父类的形参列表一致
抽象
抽象引入
抽象方法引入:如果某个方法的方法体无法确定,我们需要把这个方法定义为抽象方法。
修饰符 abstract 返回值类型 方法名(形参列表);
抽象类引入:一旦一个类含有抽象方法,那么这个类必须是抽象类。
抽象类无法创建对象,因为抽象类里的抽象方法调用没有意义。
抽象类定义一般是作为体系的规范,约束子类必须实现父类的某些方法。
我们一般不直接使用抽象类而是通过创建它的子类对象去使用。
抽象产生
当编写一个类时,我们往往会为该类定义一些方法,这些方法是用来描述该类的功能具体实现方式,那么这些方法都有具体的方法体。
但是有的时候,某个父类只是知道子类应该包含怎么样的方法,但是无法准确知道子类如何实现这些方法。比如一个图形类应该有一个求周长的方法,但是不同的图形求周长的算法不一样。那该怎么办呢?
分析事物时,发现了共性内容,就出现向上抽取。会有这样一种特殊情况,就是方法功能声明相同,但方法功能主体不同。那么这时也可以抽取,但只抽取方法声明,不抽取方法主体。那么此方法就是一个抽象方法。
当定义了抽象函数的类也必须被abstract关键字修饰,被abstract关键字修饰的类是抽象类。
接口
概述
1.接口也是一种引用数据类型,引用数据类型可以赋值null或者对象(内存中的地址)。
2.接口的出现是为了弥补java中只有单继承的不足。
格式
//类的定义格式
class 类名{
成员变量
成员方法
}
//接口的定义格式
interface 接口名{
成员变量
成员方法
}
class 类名 implements 接口名{ //类与类使用extends,类与接口使用implements
}
接口和抽象类一样,都不能创建对象。
接口编译之后也是生成 接口名.class文件
接口中的变量必须初始化才能定义(接口中的成员变量加的有默认修饰符:public static final)
static修饰的成员可以通过类名或者接口名直接调用 接口名/类名.成员变量。
final修饰的变量都是常量(只能赋值一次)。
接口中的成员方法
1.抽象方法
在接口中,定义抽象方法可以不用加public abstract,编译器默认会加。
interface MyInter{
public abstract void method();
void show();
}
class A implements MyInter{
@Override
public void method() {
System.out.println("A实现了MyInter方法");
}
@Override
public void show() {
System.out.println("A实现了show方法");
}
}
public class Demo03 {
public static void main(String[] args) {
A a = new A();
a.method();
a.show();
}
}
//执行结果
A实现了MyInter方法
A实现了show方法
2.默认方法
JDK8及以上版本才能定义默认方法
默认方法可以有方法体
默认方法可以被子类重写
当我们在接口中添加默认方法,所有的子类可以直接沿用,不需要再修改子类的代码,提高了代码的复用性。
default 返回值类型 方法名(形参列表) {
}
3.私有方法
JDK9及以上版本才能在接口中定义私有方法。
接口中的私有方法只能在本接口中使用,不能被子类使用
private 返回值类型 方法名(形参列表) {}
类与接口
一个类可以实现多个接口(一个类只能继承一个类)
//格式
class 类名 implements 接口1,接口2,...{
//重写方法
}
一个类可以继承另一个类同时实现多个接口
//格式
class 类名1 extends 类名2 implements 接口1,接口2,...{
}
一个接口可以继承多个接口
//格式
interface 接口名1 extends 接口名2,借口名3,... {
}
多态
多态概述
多态就是一个对象的多种形态。(婴儿,学生,父亲,爷爷)
多态体现
向上转型(子类型自动提升父类型)
不能将父类对象 赋值给子类型
普通类的向上转型:父类型 引用变量名 = new 子类();
Dog dog = new Dog();//我们看到一条狗,把它称作狗
Animal anmial = new Dog;//我们看到一只狗,把它称作动物
Dog dog = new Animal();//语法有误,我们看到一只动物,我们把它叫作狗
抽象类的向上转型:抽象父类型 引用变量名 = new 子类();
Teacher teacher = new Teacher();//存在一位老师,叫他老师
Person person = new Teacher();//存在一位老师,叫他人
Teacher teacher = new Person();//语法有误,存在一个人,叫他老师
接口的向上转型:父接口型 引用变量 = new 实现类();
Smoking smoking = new Student();//有个学生,抽烟
向下转型
格式:子类型 引用变量 = (子类型) 父类型引用变量 ;
(类似: int i = (int)d)
/*
*这个例子中我们只有一个学生对象
*但是这个学生对象扮演了两种角色,分别是人和学生
*当扮演人的角色的时候就具有人的行为
*当扮演学生的角色的时候就具有学生的行为
*/
class Person {
public void eat() {
System.out.println("吃东西");
}
}
class Student extends Person {
public void study() {
System.out.println("学java");
}
}
public class Demo {
public static void main(String[] args) {
Person person = new Student();//我们把生活中的一个学生看成一个人
//类比基本数据类型:double d = 3; (int =>double)
//把父类型看成大类型,把子类型看成小类型
//Student =>Person
person.eat();//由于p指向的学生对象扮演的是人的角色,所以可以调用Person类中的方法。p.study();由于p指向的学生对象扮演的是人的角色,但是Person类不具有学生的学习方法,不能调用。
Student student = (Student) person;//类比基本数据类型:int i = (int)d (double => int)
//Person => Student
student.eat();//把s指向的学生对象扮演的是学生角色,所以可以调用学生类中的方法
student.study();
}
}