JavaSE笔记11 代码块+继承+final关键字
文章目录
Part1:代码块:
在Java中,使用{}括起来的代码被称为代码块,其中根据代码块定义的位置不同以及代码块的功能和效果的不同将代码块分为三类:
- 局部代码块
- 构造代码块
- 静态代码块
一.局部代码块:
局部代码块:定义在方法中的代码块,有利于代码中资源的及早释放
案例演示:
public class CodeBlockTest {
public static void main(String[] args) {
//局部代码块:定义在类中方法外的代码块
{
int elem=100;
System.out.println("局部代码块中elem="+elem);
}
}
}
二.构造代码块:
构造代码块:定义在类中方法外的代码块,每次创建对象都会进行调用,优先于构造的方法调用
public class CodeBlockTest {
public static void main(String[] args) {
Test test = new Test();
Test test1 = new Test();
}
}
class Test{
//构造代码块
{
System.out.println("我是构造代码块");
}
//构造方法
public Test(){
System.out.println("我是构造方法");
}
}
由上面的案例演示可知,对于一个类中同时出现构造代码块以及构造方法时,在实例化该类的对象时,优先执行构造代码块,后执行构造方法
三.静态代码块:
静态代码块:在类中方法外出现,加了static修饰,并且在类中方法外出现,并加上static修饰;用于给类进行初始化,在加载的时候就执行,并且只执行一次
public class CodeBlockTest {
public static void main(String[] args) {
Test test = new Test();
Test test1 = new Test();
}
}
class Test{
//构造代码块
{
System.out.println("我是构造代码块");
}
//静态代码块
static {
System.out.println("我是静态代码块");
}
public Test(){
System.out.println("空参构造方法");
}
}
由上面的案例演示可知,当静态代码块,构造代码块,构造方法同时出现时,执行顺序是:静态代码块优先于构造代码块优先于构造方法,并且静态代码块随着类的加载而加载,最先执行且仅执行一次(.class文件只能加载一次),注意静态代码块中只能访问静态成员
四.代码块之间的顺序练习:
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();
}
}
运行结果:
上述程序练习中注意的点有:静态代码块优先于构造代码块优先于构造方法,静态代码块仅在类加载的时候初始化一次,注意加载类的先后顺序
Part2:继承
一.继承的概念引入:
1.继承的引入:
在生活中,有形形色色的继承,最常见的继承是一个家族财产的继承关系,儿子可以继承父亲的财产。在Java中也存在继承关系,Java中的继承是子类可以继承父类的成员(成员变量与成员方法)。
Java中继承关系的语法为:
用extends关键字来进行继承,让类与类之间产生继承关系
class 子类名 extends 父类名 {}
如:已存在class A{}
使用class B extends A{}
即可让B继承A
下面我们先用生活中一个简单的例子来引入Java中的继承关系:
我们知道动物里面有很多类别,例如猫,狗之类的,都有一些共性的东西。例如吃饭,睡觉等。那么我们就可以将这些共性的东西向上抽取到Animal这个类中,在子类中直接就会继承,可以大量的减少代码量,实现代码的复用性与维护性:
//父类:
public class Anmial {
//将子类共有的东西向上抽取到父类,以实现代码的复用性与维护性
public String name;
public int age;
public void eat(){
System.out.println("吃饭");
}
public void sleep(){
System.out.println("睡觉");
}
}
//子类:
public class Cat extends Anmial {
//子类中可以保留自己特有的方法
public void catchMouse(){
System.out.println("猫抓老鼠");
}
}
public class Dog extends Anmial {
public void lookDoor(){
System.out.println("小狗看门");
}
}
//测试类:
public class MyTest {
public static void main(String[] args) {
Cat cat = new Cat();
cat.name="胖橘";
cat.age=3;
System.out.println(cat.name);
System.out.println(cat.age);
cat.eat();
cat.sleep();
cat.catchMouse();
System.out.println("================");
Dog dog = new Dog();
dog.name="小强";
dog.age=5;
System.out.println(dog.name);
System.out.println(dog.age);
dog.eat();
dog.sleep();
dog.lookDoor();
}
}
对于上面的程序,运行结果为:
运行的结果为:
胖橘
3
吃饭
睡觉
猫抓老鼠
================
小强
5
吃饭
睡觉
小狗看门
2.继承的好处与弊端:
- 继承的好处:提高了代码的复用性,提高了代码的维护性,让类与类之间产生了关系,是多态的前提
- 继承的弊端:类的耦合性增强了,由于开发的原则是高内聚,低耦合,所以继承在一定程度上与开发的原则相悖(耦合:类与类的关系;内聚:就是自己完成某件事情的能力)
二.Java中继承的特点:
- Java只支持单继承,不支持多继承,但是支持多层继承,即:父类也可以继承另一个父类,有些语言是支持多继承,格式:extends 类1,类2…
- 子类只能继承父类所有非私有的成员(成员方法和成员变量)
- 构造方法不参与继承,静态方法可以继承
- Object是Java继承体系当中的顶层父类,所有的类都是直接或间接继承自他
public class ExtendTest extends Object{
public static void main(String[] args) {
D d = new D();
d.hehe();
D.hehe();
}
}
class A extends Object{
//子类不能继承父类中的私有变量
private int a=10;
public void a(){
}
}
class B extends A{
int b=100;
//子类不能继承父类的私有方法
private void b(){}
}
class C extends B{
int c=70;
public static void hehe(){
System.out.println("hehe");
}
}
class D extends C{}
三.继承中的变量:
有以下几种情形:
- 子类中的成员变量和父类中的成员变量名称不一样
- 子类中的成员变量和父类中的成员变量名称一样
- 在子类中访问一个变量的查找顺序(“就近原则”):
(1) 在子类的方法的局部范围找,有就使用
(2) 在子类的成员范围找,有就使用
(3) 在父类的成员范围找,有就使用
(4) 如果还找不到,就报错
public class TestVariable {
public static void main(String[] args) {
Son son = new Son();
son.getNum(50);
}
}
class Father{
int num=1000;
}
class Son extends Father{
int num=10;
public void getNum(int num){
System.out.println(num);
//使用this关键字访问的是本类中的成员对象
System.out.println(this.num);
//使用super关键字访问的是父类中的成员变量
System.out.println(super.num);
}
}
四.this,super关键字:
关键字 | super和this的区别 |
---|---|
super | 代表的是父类存储空间的标识(可以理解成父类的引用,可以操作父类的成员) |
this | 代表的是本类对象的引用 |
动作 | super和this的不同效果 |
---|---|
调用成员变量 | this.成员变量 调用本类的成员变量 |
super.成员变量 调用父类的成员变量 | |
调用构造方法 | this(…) 调用本类的构造方法 |
super(…) 调用父类的构造方法 | |
调用成员方法 | this.成员方法 调用本类的成员方法 |
super.成员方法 调用父类的成员方法 |
案例演示:
public class TestForThisAndSuper {
public static void main(String[] args) {
ZZ zz = new ZZ();
zz.ziHeHe(140);
}
}
class FF{
int num=20;
private int bb=250;
public int cc=1405;
public void fuShow(){
System.out.println(num+"父类的方法");
}
public int getBB(){
return this.bb;
}
}
class ZZ extends FF{
int z=100;
int num=800;
public void ziHeHe(int num) {
System.out.println(num);//140
System.out.println(this.num);//800
System.out.println(super.num);//20
System.out.println(cc);
}
public void ziShow(){
System.out.println(this.z);
System.out.println(this.num);
System.out.println(super.num);
this.fuShow();
super.fuShow();
// System.out.println(super.bb); 报错
int bb = this.getBB();
int bb1 = super.getBB();
System.out.println(bb);
System.out.println(bb1);
}
}
五.继承中的构造方法:
当我们创建子类对象时,会先调用父类的构造方法的原因:当我们去创建子类对象时,子类会继承父类的一些数据,会先完成父类数据的初始化,然后初始化自己的数据
父类没有无参构造方法,子类怎么办?
- 在父类中添加一个无参的构造方法
- 子类通过super去显示调用父类其他的带参的构造方法
- 子类通过this去调用本类的其他构造方法
案例演示1:
public class Gouzao {
public static void main(String[] args) {
Zi zi = new Zi();
Zi zi1 = new Zi(10);
Zi zi2 = new Zi(100,200);
}
}
class Fu{
public Fu(){
System.out.println("我是父类的无参构造");
}
public Fu(int x){
System.out.println("有参构造,参数为:"+x);
}
}
class Zi extends Fu{
int y,z;
public Zi(){
super(5);
System.out.println("我是子类无参构造");
}
public Zi(int y){
super();
System.out.println("我是子类有参构造:"+y);
}
public Zi(int y,int z){
this();
System.out.println("双参构造调本类"+this.y+" "+this.z);
}
}
案例演示2:关于继承的面试题:
class FuTest {
static {
System.out.println("静态代码块Fu"); //1
}
{
System.out.println("构造代码块Fu"); //3
}
public FuTest() {
System.out.println("构造方法Fu"); //4
}
}
class ZiTest extends FuTest {
static {
System.out.println("静态代码块Zi");//2
}
{
System.out.println("构造代码块Zi"); //5
}
public ZiTest() {
super();
System.out.println("构造方法Zi"); //6
}
}
public class Test{
public static void main(String[] args){
ZiTest z = new ZiTest(); //请问执行结果。
}
}
六.方法重写:
在继承关系中,当子类与父类存在一模一样的方法,可以进行方法重写
- 方法重写:子类中出现与父类一模一样的方法(方法名,参数列表以及返回值的类型),也称为方法重写或者方法覆盖
- 子类会覆盖父类的方法,实际运行时,运行的是子类重写过的方法
- 方法重写的机制:一个父类会有多个子类,父类里面抽取的是所有子类共性的功能,但每个子类对于共性功能的具体实现,存在差异
- 子类方法重写的目的:就是对父类功能实现不满意,想要根据自己的需求,进行重写与扩展
1.方法功能重写:
使用@Override可以帮忙检测是否重写方法为父类中有的方法,并且进行功能重写时需要对其中的方法体进行重写,对于方法体重新改写:
class Animal{
public void eat(){
System.out.println("我爱吃骨头");
}
public void run(){
System.out.println("我用四肢走路");
}
}
class Dog extends Animal{}
class Bird extends Animal{
@Override
public void eat() {
System.out.println("我爱吃虫子");
}
@Override
public void run() {
System.out.println("我用两双翅膀飞");
}
}
public class TestOverride {
public static void main(String[] args) {
Dog dog = new Dog();
dog.eat();
dog.run();
System.out.println("--------------------------------");
Bird bird = new Bird();
bird.eat();
bird.run();
}
}
2.方法功能拓展:
功能拓展使用ctrl+o选择需要重写的方法并进行重写,保留其中的第一句:super.父类方法就可以进行拓展了:
public class Test {
public static void main(String[] args) {
Cat cat = new Cat();
cat.eat();
cat.name();
}
}
class Animals{
public void eat(){
System.out.print("我爱吃");
}
public void name(){
System.out.print("我是");
}
}
class Cat extends Animals{
@Override
public void eat() {
super.eat();
System.out.println("鱼");
}
@Override
public void name() {
super.name();
System.out.println("猫");
}
}
3.重写的注意事项:
注意事项:
- 父类中私有方法不能被重写,因为父类私有方法子类根本就无法继承
- 子类重写父类方法时,访问权限不能更低,最好就一致
- 父类静态方法,不参与重写,其实这个算不上方法重写,但是现象确实如此
- 子类重写父类方法的时候,最好声明一模一样
public class MyTest {
public static void main(String[] args) {
Father.haha();
Son son = new Son();
son.haha();
Son.haha();
}
}
class Father{
private void show(){
}
protected void hehe(){
}
public static void haha(){
System.out.println("父类的静态方法");
}
}
class Son extends Father{
@Override
protected void hehe() {
}
//@Override 静态方法不参与重写
public static void haha() {
System.out.println("子类的静态方法");
}
}
七.final关键字:
1.final关键字概述:
由于继承中有一个方法重写的现象,而有时候我们不想让子类去重写父类的方法.这对这种情况java就给我们提供了一个关键字: final,final关键字是最终的意思,可以修饰类,变量,成员方法
2.final关键字的修饰特点:
final修饰 | 效果 |
---|---|
修饰类 | 被修饰类不能被继承 |
修饰方法 | 被修饰的方法不能被重写 |
修饰变量 | 被修饰的变量不能被重新赋值,因为这个量其实是一个常量 |
3.final关键字修饰局部变量:
- final修饰基本类型,是值不能被改变
- final修饰引用类型,是地址值不能被改变
案例演示:
public class MyTest2 {
public static final double AA=3.14;
public static void main(String[] args) {
final int NUM=100;
System.out.println(NUM);
BB bb = new BB();
System.out.println(bb);
bb=new BB();
System.out.println(bb);
System.out.println("============================");
final BB bb1 = new BB();
CC cc = new CC();
cc.show();
}
}
class BB{
public final void show(){
System.out.println("父类的final修饰的方法,子类不能重写,子类可以继承");
}
}
class CC extends BB{
/* @Override
public void show() {
}*/
}
//final修饰类,此类不能被继承
final class EE{
}
/*
class FF extends EE{
}
*/