面向对象day10
一.Math的介绍
1. Math: 是属于java.lang包下的,所以将来使用的时候不需要导包Math类包含执行基本数字运算的方法,如基本指数,对数,平方根和三角函数。
注意:
Math类没有构造方法,因为它的成员变量和成员方法都是被static修饰 可以直接通过类名.静态成员的方式进行访问。
掌握一个方法:random() 获取随机数
返回一个double值为正号,大于等于0.0 ,小于1.0 [0.0,1.0)
2.举例
猜数字小游戏(1-100)
分析:Math.random()*100+1就能取到1-100;
1、使用Math类中的random()方法获取一个随机数,经过转换得到1-100之间的数 random
2、键盘录入猜的数据 number
3、将我们猜的数据与随机生成的数据进行比较
number > random:猜的数字大了
number < random:猜的数字小了
number == random:恭喜你,猜对了
4、多给几次机会,直到猜中,由于不知道要猜多少次,用while循环
import java.util.Scanner;
public class GuessNumer {
public static void main(String[] args) {
//Math类使用random()方法产生1-100随机数
int random = (int) (Math.random() * 100 + 1);
System.out.println("随机数已经生成,请开始猜。。。。。");
//键盘对象
Scanner sc = new Scanner(System.in);
while (true) {
System.out.println("请输入一个数据:");
int number = sc.nextInt();
if (number > random) {
System.out.println("您猜的数据大了,请往小了的猜.");
} else if (number < random) {
System.out.println("您猜的数据小了,请往大了的猜.");
} else {
System.out.println("恭喜你,猜中了,奖励保时捷5元代金券,猜中的数字为:" + random);
break;
}
}
}
}
二.代码块的优先级介绍
(1) 代码块:在Java中,使用{}括起来的代码被称为代码块,根据其位置和声明的不同, 可以分为局部代码块,构造代码块,静态代码块,同步代码块(多线程讲解)。
-
局部代码块:在方法中出现,限定变量的生命周期,及早释放,提高内存的利用在同一个类中的同一个方法中,如果存在多个局部代码块,执行顺序是自上而下的。在类中的方法内部。
-
构造代码块:(在创建对象的时候调用)
定义在类中方法外。当一个类中既存在构造代码块也存在构造方法的时候,在创建对象时,会先执行构造代码块,后执行构造方法。
无论类中有多少个构造代码块,构造代码块之间会先进行自上而下的顺序执行,然后再执行构造方法。构造代码块 – 构造方法 -
静态代码块:
在类中方法外定义,并加上static修饰。静态代码块是优先于其他代码块之前执行,在类中方法外部。
静态代码块 – 局部代码块 – 构造代码块 – 构造方法
在加载的时候执行,并且只执行一次
(2)举例说明
class Student2{
static {
System.out.println("这是在Student2类中静态代码块");
// 1
}
{
System.out.println("这是在Student2类中的构造代码块");
// 2
}
Student2(){
System.out.println("这是Student2类中的无参构造方法");// 3
}//3
}
// 4 5 6 1 2 3
public class CodeTest {
static {
System.out.println("这是在CodeTest类中的静态代码块");
// 4
}
public static void main(String[] args) {
System.out.println("开始执行main方法"); // 5
{
System.out.println("这是在CodeTest中的局部代码块");
// 6
}
Student2 student2 = new Student2();
}
}
首先会执行public Class CodeTest中的static代码块,在执行main方法即5和6,然后创建对象初始化执行1,2,3
最后代码执行顺序为4,5,6,1,2,3.
三.继承
1.语句格式:class 子类名 extends 父类名{…}
class Zi extends Fu{}
这里的Zi我们称之为子类,派生类,
这里的Fu我们称之为父类,超类,基类
举例:
class Human{
String name;
int age;
//getXxx()/setXxx()
public void study(){
System.out.println("学习");
}
}
class Father extends Human{
}
class Son extends Father{
}
public class ExtendsDemo {
public static void main(String[] args) {
//创建一个父亲对象
Father f1 = new Father();
f1.study();
//创建一个儿子对象
Son s1 = new Son();
s1.study();
}
}
继承: 把多个类相同的内容提取到另外一个类中,然后使用关键字extends来实现继承
如何实现:
利用java提供的关键字:extends来实现继承
语句格式:
class 子类名 extends 父类名{}
继承的好处:
1、提高了代码的复用性 看一看父类
2、提高了代码的维护性 只需要修改父类的内容
3、让类与类之间产生了继承关系,为了后面多态做铺垫
(要有继承才能有多态)
继承的坏处:
1、类的耦合性增强了。(内聚)
开发的原则:
低耦合,高内聚
耦合:类与类之间的关系
内聚:类自己本身可以完成的事情
3. Java中继承的特点:
1、Java中的类class只支持单个继承,不允许多个继承
2、Java中的类支持多层继承(形成了一个继承体系)
举例·多层继承
class GrandFather{
public void show(){
System.out.println("我是爷爷");
}
}
class Father4 extends GrandFather{
public void show1(){
System.out.println("我是老子");
}
}
class Son4 extends Father4{
public void show2(){
System.out.println("我是儿子");
}
}
public class ExtendsDemo3 {
public static void main(String[] args) {
Son4 son4 = new Son4();
son4.show2(); //可以使用自己的方法
son4.show1(); //也可以使用父亲的方法
son4.show(); //也可以使用爷爷的方法
}
}
2.使用继承时所需要的注意事项:
(1)、要想初始化子类,必须先初始化父类 ******
举例:现有父亲,才能有儿子
(2)、子类只能继承父类的非私有的成员(成员变量和成员方法)
(3)、子类不能继承父类的构造方法,但是可以通过super关键字去访问父类的构造方法
因为要想初始化子类,必须先初始化父类,是通过构造方法进行初始化的。
(4)、不要为了部分的功能而去使用继承
(5)、那么,什么时候使用继承呢?
在英语中有一个语法叫“is a”
当两个类满足语法什么是什么的时候,就可以使用继承了
```java
class Father5{
int num = 20;
private int num2 = 30;
Father5(){
System.out.println("这是父亲的无参构造方法");
}
private void fun1(){
System.out.println(num);
}
}
class Son5 extends Father5{
public void fun2(){
System.out.println(num);
// System.out.println(num2); // 子类不能继承父类的私有成员变量
}
}
public class ExtendsDemo4 {
public static void main(String[] args) {
Son5 son5 = new Son5();
son5.fun2();
// son5.fun1(); // 子类不能继承父类的私有成员方法
}
}
继承的使用注意事项2:
类的组成:
成员变量
构造方法
成员方法
引入了继承,我们需要注意在写代码的过程中考虑继承关系带来的影响
**继承与成员变量之间的关系:**
1、当子类中的成员变量与父类中的成员变量名字一样的时候
查找:(就近原则)
1)先在方法的局部范围内进行查找,如果找到就返回
2)如果在方法局部范围找不到,去本类中成员位置上查找,如果找到
就返回
3)如果在中成员位置上找不到,去父类中成员位置上查找,如果找到就
返回
4)如果在父类中成员位置上找不到,报错。
2、当子类中的成员变量与父类中的成员变量名字不一样的时候,使用什
么变量名,就访问谁
```java
class Father6{
int num = 10;
int num2 = 200;
public void show2(){
int num = 100;
int num2 = 20;
}
}
class Son6 extends Father6{
int num = 30;
int num3 = 300;
public void show1(){
// int num = 40;
System.out.println(num);
System.out.println(num2);
System.out.println(num3);
}
}
public class ExtendsDemo5 {
public static void main(String[] args) {
Son6 son6 = new Son6();
son6.show1();
}
}
3.super和this
继承中出现的问题:
我们现在不仅仅要输出局部范围内的num,我们还想输出父类中num,怎么办呢?
如果有一个东西,根this相似,也可以代表父类的引用,通过这个东西去 访问父类中的数据就好了。
Java替你考虑到了这个问题,提供了一个关键字给我们使用:super 面试题:this关键字与super关键字的使用区别?
this代表的是调用该类的当前对象
super代表的是父类存储空间的标识(父类的引用,可以操作父类的成员)
怎么用呢?
1、访问成员变量
this.成员变量 访问的是本类中的成员变量
super.成员变量 访问的是父类中的成员变量
2、访问构造方法
this(...)
super(...)
3、访问成员方法
this.成员方法()
super.成员方法()
举例:
class Father7{
int num = 10;
public void show2(){
System.out.println("这是父类中的show2方法");
}
}
class Son7 extends Father7{
int num = 20;
public void show(){
int num = 30;
System.out.println(num);
System.out.println(this.num); // 访问的是本类中的成
//员变量如何访问到父类中的同名成员变量呢?
System.out.println(super.num);// 访问的是父类中的成员变量
show2();
super.show2();//访问父类的成员方法
show3();
this.show3();
}
public void show3(){
System.out.println("这是Son7类中的show3方法");
}
}
public class ExtendsDemo6 {
public static void main(String[] args) {
Son7 son7 = new Son7();
son7.show();
}
}
4. 继承与构造方法的关系:
(1)
1、要想初始化子类,必选先初始化父类
2、为什么?
因为子类会继承父类的数据,甚至可能会使用父类的数据
所以在子类初始化之前,一定会先完成父类的初始化
注意: 每个子类的构造方法的第一句话默认是super().
举例:
public class ExtendsDemo08 {
public static void main(String[] args) {
Son4 s1=new Son4();
System.out.println("下面是有参的情况");
Son4 s=new Son4("xiaoming");
}
}
class Father4{
Father4(){
System.out.println("这是父类的无参构造方法!!!");
}
Father4(String name){
System.out.println("这是父类有参构造方法!!!"+name);
}
}
class Son4 extends Father4{
Son4( ){//有一句默认的super()
System.out.println("这是子类的无参构造方法!!!");
}
Son4(String name){super("xiaoming");
System.out.println("这是子类的有参方法!!!!"+name);
}
}
图1
(3)当父类中没有无参构造方法的时候,怎么办呢?
-
使用super关键字带参数的形式访问父类的带参数构造方法
-
子类通过this关键字调用本类的其他构造方法
注意,本类其他构造方法也必须可以访问父类拥有的构造方法
使用this关键字间接的调用父类的构造方法
无论在哪里调用父类的构造方法,只要最后保证在子类构造方法内容执行之前完成了父类的初始化就可以了 -
super(…)或者this(…)必须出现在第一条语句上,否则就会出现父类的数据进行了多次初始化
(重点)每个类只能初始化一次
举例:
public class ExtendsDemo09 {
public static void main(String[] args) {
Son05 s=new Son05("马院");
}
}
class Father5{
Father5(String name){
System.out.println("这是父类的有参构造方法"+name);
}//1
}
class Son05 extends Father5{
Son05(){
super("马院");//没有这句的话程序就会报错
System.out.println("这是子类的无参构造方法!!!");//2
}
Son05(String name){
this();//调用了本类中的Son05这个无参构造方法,因此他会
//先将父类初始化,因为父类中没有无参构造方法所以利用super手动调用父
//类唯一的有参构造方法
System.out.println("这是子类的有参构造方法!!!"+name);//3
}
}
this():调用了本类中的Son05这个无参构造方法,因此他会先将父类初始化,因为父类中没有无参构造方法所以利用super手动调用父类唯一的有参构造方法.
图2
5. 继承与成员方法的关系:
(1)、当子类的成员方法名与父类成员方法名不一样的时候,该调用谁就调用谁的
(2)、当子类的成员方法名与父类成员方法名一样的时候,怎么办呢?(就近原则)
1)现在本类中查找,如果有就调用,如果没有去父类中查找,
2)如果父类中有方法,就调用父类的
3)如果连父类中都没有要调用的方法名,报错,提示找不到方法。
举例:
public class ExtendsDemo10 {
public static void main(String[] args) {
Son6 s=new Son6();
s.show();
s.show1();
}
}
class Father6{
public void show(){
System.out.println("这是父类中的show方法!!!");
}
}
class Son6 extends Father6{
//public void show(){
// System.out.println("这是子类中的show方法!!!");
//}
public void show1(){
System.out.println("这是子类中的show1方法!!!");
}
}
图三
6.重写与重载的区别
子类的方法名能不能和父类方法的声明一样?
如果子类的方法声明与父类的方法声明一样,这样的现象叫做方法的重写。
重写现象是发生在继承的关系中。
面试题:
重写与重载的区别:
重写是发生在继承的关系的关系中,重载是发生在本类中。
重载是方法名一致,参数列表不一致就是重载。
重写是方法名,参数列表,返回值都一样,实现不一样,叫方法的
重写。
重载的英文单词:overload
重写的英文单词:override
重写的举例:
public class ExtendsDemo11 {
public static void main(String[] args) {
Son7 s=new Son7();
s.call("院长");
}
}
class Father7{
public void call(String name){
System.out.println("打电话给:"+name);
}
}
class Son7 extends Father7{
@Override
public void call(String name) {
super.call(name);
System.out.println("打游戏");
System.out.println("刷抖音");
}
}
图四
7.综合举例
(1)
public class ExtendDemo12 {
public static void main(String[] args) {
Son8 s=new Son8();
s.show();
}
}
class Father8{
int num=10;
Father8(){
System.out.println("这是父类的无参构造方法");//1
}
}
class Son8 extends Father8{
int num=100;//4
Son8(){
System.out.println("这是子类的无参构造方法");//2
}
public void show(){
int num=30;//3
System.out.println(num);//30
System.out.println(this.num);//100 注意如果你将3中
// 的int去掉这句话的输出结果结尾30,这指的是将4中的num改为了30。
System.out.println(super.num);//10
}
}
图五
(2)
一个类的初始化过程:
1、栈开辟空间
2、堆开辟空间给对象
3***、成员变量的值是系统默认值
4、成员变量显式赋值***
5、构造方法赋值
class X {
Y b = new Y(); // 1
X() {
System.out.print("X"); // 3
}
}
class Y {
Y() {
System.out.print("Y"); //2
}
}
class Z extends X{
Y y = new Y();//4
Z(){
// super(); //这里的super()存在的意义不大 因为已经初始化过了。
System.out.println("Z");//5
}
}
public class ExtendDemo13{
public static void main(String[] args) {
new Z();//从z开始,由于z继承x所以要先将x初始化,又因为成员变量显式赋值优先于构造方法赋值所以先执行1,而1中又是对Y初始化所以要执行Y类中的构造方法2输出y
//再执行X的构造方法输出x,这样X完成初始化。然后在完成z中的显示赋值4输出y,再输出z。
}
}
从z开始,由于z继承x所以要先将x初始化,又因为成员变量显式赋值优先于构造方法赋值所以先执行1,而1中又是对Y初始化所以要执行Y类中的构造方法2输出y
再执行X的构造方法输出x,这样X完成初始化。然后在完成z中的显示赋值4输出y,再输出z。
总结:无论成员变量显式赋值、还是构造方法赋值,有继承关系时当对之类初始化时一定首先要对父类初始化,此优先级最高,然后再想着显式赋值优先级高于构造方法赋值。
最终结果为:yxyz