面向对象
构造方法的概述与格式
构造方法的概述和作用:
创建对象,给对象中的成员进行初始化
构造方法格式特点:
-
方法名与类名相同
-
没有返回值类型,不用void
-
没有具体的返回值
构造方法的重载(创建不同的用户对象):
- 如果方法构造中形参名与属性名相同时,需要使用this关键字区分属性与形参。
this关键字:
- this的作用是在类中通过this访问自身的属性和方法。
String name = "李四"; //定义一个成员变量name
public Student(String name) { //定义一个参数(局部变量)name
this.name = name; //将局部变量的值传递给成员变量
}
/** 有一个成员变量name,同时在方法中也有一个形参叫name,然后将方法中的形参传递给成员变name;this.name代表的就是对象中的成员变量,又叫做对象的属性,而后面的name则是方法的形式参数,this.name=name就是将形式参数的值传递给成员变量*/
public:
- 公共的,可以被同一项目下的任何类所调用,一般用于对外的情况。
private:
- 只为类本身提供。是一种封装的体现。
get,set方法:
- get和set方法一般是用于封装类的属性,将属性私有化,然后通过set 和 get 方法。
实例(学生类)
public class Student {
private String name ; //设私有变量name
private int age; //设私有变量age
public void setName(String name) { //定义set方法
this.name = name; //将局部变量的值传递给成员变量
}
public String getName(){ //定义get方法
return name;
}
public void setAge(int age) {
this.age = age;
}
public int getAge() {
return age;
}
public void show(){
System.out.println("姓名:"+name+"=====年龄:"+age);
}
}
public class MyTest {
public static void main(String[] args) {
Student s = new Student(); //创建对象
s.setName("张三"); //调用set方法并传参张三给name
s.setAge(50); //调用set方法并传参50给age
s.show();
}
}
运行结果:
姓名:张三=====年龄:50
/**该类中有name,age是私有变量,然后我定义setage()、getage()这两个方法,通过这两个方法来实现对name,age的操作。main函数中使用调用setage方法并传参(张三),然后setage方法将张三设置给了name,调用setage方法并传参(50),然后setage方法将50设置给了age;然后main函数使用getage方法获取name和age的值。所以输出结果为 张三,50 。通过set和get方法间接地操作这些变量,这样就能提高域变量的安全性,同时又保证了域变量的封装型。*/
创建一个对象的步骤
- Student s=new Student();
(1):加载Student.class文件进内存
(2):在栈内存为s开辟空间
(3):在堆内存为学生对象开辟空间
(4):对学生对象的成员变量进行默认初始化
(5):对学生对象的成员变量进行显示初始化
(6):通过构造方法对学生对象的成员变量赋值
(7):学生对象初始化完毕,把对象地址赋值给s变量
static关键字:
static关键字,告知编译器main函数是一个静态函数。也就是说main函数中的代码是存储在静态存储区的,静态方法在内存中的位置是固定的,即当定义了类以后这段代码就已经存在了。如果main()方法没有使用static修饰符,那么编译不会出错,但是如果你试图执行该程序将会报错,提示main()方法不存在。因为包含main()的类并没有实例化(即没有这个类的对象),所以其main()方法也不会存。而使用static修饰符则表示该方法是静态的,不需要实例化即可使用。
1.static 修饰的域,我们叫静态域,它是归类所有的,被所有对象所共享,只有一个
2.static修饰的区块,域只会初始化一次
3.static修饰的域或方法,可以直接通过类的名字加上.进行调用
4.static修饰的方法内不能直接使用非静态成员
实例:
public lass Person {
public String name;
//static 静态的,可以修饰成员变量和成员方法,修饰成员变量,
// 此变量就为一个共享变量,会被这个类的所有对象,所共享。
public static String country = "中国";
}
public class MyTest {
public static void main(String[] args) { //静态的变量,通过类名直接调用,不需要new对象。
Person.country="美国";
Person p1 = new Person();
p1.name = "张三";
Person p2 = new Person();
p2.name = "李四";
Person p3 = new Person();
p3.name = "王五";
//让多个对象,去共享国籍这个数据。
System.out.println(p1.name);
System.out.println(p1.country);
System.out.println("======================");
System.out.println(p2.name);
System.out.println(p2.country);
System.out.println("======================");
System.out.println(p3.name);
System.out.println(p3.country);
System.out.println("=========================================");
System.out.println(Person.country);
注意事项:
1.在静态方法中是没有this关键字的
2.静态是随着类的加载而加载,this是随着对象的创建而存在。静态比对象先存在。
3.静态方法只能访问静态的成员变量和静态的成员方法
简单记:静态只能访问静态,非静态可以访问静态的也可以访问非静态的
Math类的随机数功能
- 打开jdk查询math类
案例演示:
需求:猜数字小游戏(数据在1-100之间)
public class shuzi {
public static void main(String[] args) {
int num = (int) (Math.random() * 100 + 1);
for (int i = 1; i <= 10; i++) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入一个你要猜的整数 1---100");
int userNum = sc.nextInt();
if (userNum > num) {
System.out.println("你猜大了");
} else if (userNum < num) {
System.out.println("你猜小了");
} else {
System.out.println("恭喜你,猜对了");
}
}
}
}
代码块
-
代码块概述
在Java中,使用{}括起来的代码被称为代码块。 -
代码块分类
根据其位置和声明的不同,可以分为局部代码块,构造代码块,静态代码块,同步代码块(多线程讲解) -
常见代码块的应用
a:局部代码块
在方法中出现;限定变量生命周期,及早释放,提高内存利用率
b:构造代码块 在类中方法外出现;多个构造方法方法中相同的代码存放到一起,每次调用构造都执行,并且在构造方法前执行
c:静态代码块
在类中方法外出现,加了static修饰
在类中方法外出现,并加上static修饰;用于给类进行初始化,在加载的时候就执行,并且只执行一次。
案例(测试题)
A:看程序写结果
class Student {
static {
System.out.println("Student 静态代码块"); //3
}
{
System.out.println("Student 构造代码块"); //4 6
}
public Student() {
System.out.println("Student 构造方法");//5 7
}
}
class StudentDemo {
static {
System.out.println("StudentDemo的静态代码块"); //1
}
public static void main(String[] args) {
System.out.println("我是main方法"); //2
Student s1 = new Student();
Student s2 = new Student();
}
}
继承
1.继承的基本格式: 通过extends关键字可以实现类与类的继承 ;
class 子类名 extends 父类名 {}
2.继承的概念:多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和行为,只要继承那个类即可。
this与super关键字
- this 代表的是本类对象的引用
- super 代表的是父类存储空间的标识(可以理解成父类的引用,可以操作父类的成员)
- this和super的使用
a:调用成员变量
this.成员变量 调用本类的成员变量
super.成员变量 调用父类的成员变量
b:调用构造方法
this(…) 调用本类的构造方法
super(…) 调用父类的构造方法
c:调用成员方法
this.成员方法 调用本类的成员方法
super.成员方法 调用父类的成员方法
3.继承的注意事项
a:子类只能继承父类所有非私有的成员(成员方法和成员变量)
b:子类不能继承父类的构造方法,但是可以通过super关键字去访问父类构造方法。
c:不要为了部分功能而去继承
4.继承中成员变量的关系:
A:子类中的成员变量和父类中的成员变量名称不一样
B:子类中的成员变量和父类中的成员变量名称一样
在子类中访问一个变量的查找顺序(“就近原则”)
a: 在子类的方法的局部范围找,有就使用
b: 在子类的成员范围找,有就使用
c: 在父类的成员范围找,有就使用
d:如果还找不到,就报错
5.继承中构造方法的关系:
子类中所有的构造方法默认都会访问父类中空参数的构造方法
因为子类会继承父类中的数据,可能还会使用父类的数据。
所以,子类初始化之前,一定要先完成父类数据的初始化。
每一个构造方法的第一条语句默认都是:super()
6.继承中成员方法的关系:
当子类的方法名和父类的方法名不一样的时候
当子类的方法名和父类的方法名一样的时候
通过子类调用方法:
a: 先查找子类中有没有该方法,如果有就使用
b:在看父类中有没有该方法,有就使用
案例
class Fu{
public int num = 10;
public Fu(){
System.out.println("fu");
}
}
class Zi extends Fu{
public int num = 20;
public Zi(){
System.out.println("zi");
}
public void show(){
int num = 30;
System.out.println(num); //30
System.out.println(this.num); //20
System.out.println(super.num); //10
}
}
class Test {
public static void main(String[] args) {
Zi z = new Zi();
z.show();
}
}
运行结果为:
fu zi 30 20 10
方法重写
概念:Override;子类中出现了和父类中一模一样的方法声明(方法名,参数列表,返回值类型),也被称为方法覆盖,方法复写。
应用:当子类需要父类的功能,而功能主体子类有自己特有内容时,可以重写父类中的方法。
这样,即沿袭了父类的功能,又定义了子类特有的内容。
注意事项:
1.父类私有的方法子类不能重写
2.构造方法,静态方法,不参与重写。
3.子类重写父类方法时,方法的权限修饰符,不能比父类的低,要比父类的高,或者一样。
4.父类final修饰的方法子类不能重写。
方法重载:允许在一个类中定义多个同名方法,只有他们的参数列表不同(个数不同或数据类型不同)
重载和重写的区别:
- 作用范围:重写的作用范围是父类和子类之间;重载是发生在一个类里面
- 参数列表:重载必须不同;重写不能修改
- 返回类型:重载可修改;重写方法返回相同类型或子类
- 抛出异常:重载可修改;重写可减少或删除,一定不能抛出新的或者更广的异常
- 访问权限:重载可修改;重写一定不能做更严格的限制
案例
public class Animal {
public void sleep(){
System.out.println("睡觉");
}
public void eat(){
System.out.println("吃饭");
}
}
public class Cat extends Animal{
@Override
public void eat(){
System.out.println("猫吃鱼");
}
//Ctrl+O 重写父类的方法
@Override //@Override 注解 作用:用来检测这个方法,是不是重写父类的。
public void sleep() {
System.out.println("猫白天睡觉");
}
final关键字:
由于继承中有一个方法重写的现象,而有时候我们不想让子类去重写父类的方法.这对这种情况java就给我们提供了一个关键字: final
final关键字是最终的意思,可以修饰类,变量,成员方法。
A:final修饰特点
修饰类: 被修饰类不能被继承
修饰方法: 被修饰的方法不能被重写
修饰变量: 被修饰的变量不能被重新赋值,因为这个量其实是一个常量
多态
1.概念:某一个事物,在不同时刻表现出来的不同状态。
举例: Cat c=new Cat();
Animal a=new Cat();
2.多态的前提:
a:要有继承关系。
b:要有方法重写。 其实没有也是可以的,但是如果没有这个就没有意义。
c:要有父类引用指向子类对象。
父 f = new 子();
3.多态中的成员访问特点:
a:成员变量
编译看左边,运行看左边。
b:构造方法
创建子类对象的时候,会访问父类的构造方法,对父类的数据进行初始化。
c:成员方法
编译看左边,运行看右边。
d:静态方法
编译看左边,运行看左边。
(静态和类相关,算不上重写,所以,访问还是左边的)
4.多态的好处:
- 能够提高代码的复用性和维护性(靠继承保证)
- 提高代码的扩展性。
5.多态的弊端以及多态中向上转型和向下转型
- 多态的弊端:不能使用子类特有的功能
Fu fu = new Zi(); //向上转型:多态就是向上转型
- 向下转型:把父类的引用强制转换为子类的引用。
//我们可以采用向下转型,那调用子类特有的功能
System.out.println(fu.num); //200
Zi zi= (Zi) fu; //把父类引用,向下转型为子类型。
zi.hehe();
System.out.println(zi.num); //10
案例
public class MyTest {
public static void main(String[] args) {
//多态的弊端:不能调用子类特有的功能
Fu fu = new Zi(); //向上转型:多态就是向上转型。
fu.show();
//多态,不能直接调用,子类特有的功能。
//fu.hehe(); 报错。
//我们可以采用向下转型,那调用子类特有的功能
System.out.println(fu.num); //200
Zi zi= (Zi) fu; //把父类引用,向下转型为子类型。
zi.hehe();
System.out.println(zi.num); //10
}
}
class Fu {
int num=200;
public void show() {
System.out.println("fu Show");
}
}
class Zi extends Fu {
int num=10;
@Override
public void show() {
System.out.println("zi Show");
}
public void hehe() {
System.out.println("子类特有的方法");
}
}
抽象类
- 在java中使用abstract class来定义抽象类。
抽象类概述:
猫狗案例,提取出了一个动物类。并且我们在前面也创建过了动物对象,其实这是不对的。
为什么呢?因为,我说动物,你知道我说的是什么动物吗?只有看到了具体的动物,你才知道,这是什么动物。
所以说,动物本身并不是一个具体的事物,而是一个抽象的事物。只有真正的猫,狗才是具体的动物。
同理,我们也可以推想,不同的动物吃的东西应该是不一样的,所以,我们不应该在动物类中给出具体体现,而是应该给出一个声明即可。
在Java中,一个没有方法体的方法应该定义为抽象方法,而类中如果有抽象方法,该类必须定义为抽象类。
抽象类特点
a:抽象类和抽象方法必须用abstract关键字修饰
抽象类格式: abstract class 类名 {}
抽象方法格式: public abstract void eat();
b:抽象类不一定有抽象方法,有抽象方法的类一定是抽象类
c:抽象类中可以有构造方法,抽象类不能进行实例化,那么要构造方法有什么作用呢?
用于子类访问父类数据时的初始化
d:抽象类不能直接实例化那么,抽象类如何实例化呢?
按照多态的方式,由具体的子类实例化。其实这也是多态的一种,抽象类多态。
e:抽象类的子类
要么是抽象类
要么重写抽象类中的所有抽象方法
抽象类的成员特点
-
抽象类的成员特点
a:成员变量:既可以是变量,也可以是常量。
b:构造方法:有。用于子类访问父类数据的初始化。
c:成员方法:既可以是抽象的,也可以是非抽象的。 -
抽象类的成员方法特性:
a:抽象方法 强制要求子类做的事情。
b:非抽象方法 子类继承的事情,提高代码复用性。
猫狗案例
public class MyTest {
public static void main(String[] args) {
//Animal animal = new Animal();
Cat cat = new Cat();
Dog dog = new Dog();
}
}
//abstract 抽象的,可以修饰类,修饰方法。
abstract class Animal {
//父类,他也不知道,子类对这个共性功能的具体实现,所以也没有必要给出共性功能的具体实现
//抽象类,抽取所有子类的共性功能,但是不给出,共性功能的具体实现,而是交由子类根据自身的特性做以具体的实现。
public abstract void eat();
public abstract void sleep();
}
class Cat extends Animal {
@Override
public void eat() {
System.out.println("猫吃鱼");
}
@Override
public void sleep() {
System.out.println("猫白天睡觉");
}
}
class Dog extends Animal {
@Override
public void eat() {
System.out.println("狗吃骨头");
}
@Override
public void sleep() {
System.out.println("狗晚上睡觉");
}
}
接口
- 接口概念:在java中接口是一个全部由抽象方法组成的集合,接口需要用interface定义,里面只有抽象方法和常量。
举例说明: 猫狗案例,我们想想狗一般就是看门,猫一般就是作为宠物了。
但是,现在有很多的驯养员或者是驯兽师,可以训练出:猫钻火圈,狗跳高,狗做计算等。而这些额外的动作,并不是所有猫或者狗一开始就具备的,这应该属于经过特殊的培训训练出来的。
所以,这些额外的动作定义到动物类中就不合适,也不适合直接定义到猫或者狗中,因为只有部分猫狗具备这些功能。
所以,为了体现事物功能的扩展性,Java中就提供了接口来定义这些额外功能,并不给出具体实现,将来哪些猫狗需要被培训,只需要这部分猫狗把这些额外功能实现即可
-
接口特点:
a:接口用关键字interface表示 格式: interface 接口名 {}
b:类实现接口用implements表示 格式: class 类名 implements 接口名 {}
c:接口不能实例化 ; 按照多态的方式来实例化。
d:接口的子类
a:可以是抽象类。但是意义不大。
b:可以是具体类。要重写接口中的所有抽象方法。(推荐方案) -
接口成员变量特点:
成员变量:只能是常量,并且是静态的。
默认修饰符:public static final
建议:自己手动给出。
构造方法:接口没有构造方法。
成员方法:只能是抽象方法。
默认修饰符:public abstract
建议:自己手动给出。
案例说明
public class MyTest {
public static void main(String[] args) {
//接口的子类有两种选择:1.重写接口中的所有抽象方法,2.自己本身就是一个抽象类 但是意义不大。
//接口中的成员特点:
//1.接口中的成员变量,全部是公共的静态常量 前面存在默认修饰符 public static final
System.out.println(A.NUM); //接口名直接调用
//2.JDK1.7 之前接口中的方法,全部是抽象方法,不存在非抽象方法。方法的前面存在 默认修饰符 public abstract
//3.接口中没有构造方法这一说。
//4.接口不能直接new对象。
}
}
interface A{
public static final int NUM=100;
public abstract void a();
public abstract void aa();
int sum(int a,int b);
}
class B implements A{
@Override
public void a() {
}
@Override
public void aa() {
}
@Override
public int sum(int a, int b) {
return 0;
}
}
- 类与类,类与接口,接口与接口的关系:
a:类与类:继承关系,只能单继承,可以多层继承。
b:类与接口:实现关系,可以单实现,也可以多实现。并且还可以在继承一个类的同时实现多个接口。
c:接口与接口:继承关系,可以单继承,也可以多继承。
抽象类和接口的区别:
A:成员区别
抽象类:
成员变量:可以变量,也可以常量
构造方法:有
成员方法:可以抽象,也可以非抽象
接口:
成员变量:只可以常量
成员方法:只可以抽象
B:关系区别
类与类
继承,单继承
类与接口
实现,单实现,多实现
接口与接口
继承,单继承,多继承
C:设计理念区别
抽象类 被继承体现的是:”is a”的关系。 抽象类中定义的是该继承体系的共性功能。
接口 被实现体现的是:”like a”的关系。 接口中定义的是该继承体系的扩展功能。
注:jdk1.8后可以有静态方法和方法体。
案例说明
动物类:姓名,年龄,吃饭,睡觉。
动物培训接口:跳高
猫继承动物类
部分猫继承猫类并实现跳高接口
跳高接口通过抽象类测试基本功能。
通过接口测试扩展功能。
public abstract class Animal {
String name;
int age;
public abstract void eat();
public abstract void sleep();
}
public interface JumpInterface {
void jump();
}
public class Cat extends Animal{
@Override
public void eat() {
System.out.println("吃饭");
}
@Override
public void sleep() {
System.out.println("睡觉");
}
}
public class 二哈 extends Dog implements JumpInterface{
@Override
public void eat() {
System.out.println("二哈 吃狗粮");
}
@Override
public void sleep() {
System.out.println("二哈在家里睡觉");
}
public void sledding(){
System.out.println("二哈 拉雪橇");
}
@Override
public void jump() {
System.out.println("二哈学会了跳高");
}
}
public class MyTest {
public static void main(String[] args) {
二哈 eh = new 二哈();
Dog dog = eh;
dog.name = "二哈";
dog.age = 2;
dog.eat();
dog.sleep();
//向下转型。
二哈 er = (二哈) dog;
er.sledding();
//er.jump();
JumpInterface jumpInterface = eh;
jumpInterface.jump();
System.out.println(eh);
System.out.println(er);
}
}