Java SE 之面向对象编程——类与对象

1.代码块
代码块定义:使用"{}"定义的一段代码
根据代码块的位置以及关键字,可以简单分

为以下四种:
a.普通代码块
b.构造块
c.静态块
d.同步代码块

普通代码块
定义:定义在方法中的代码块

public class Test1{
    public static void main(String[] args){
        //直接用{}定义,普通方法块
        {
            int x = 10;
            System.out.println("x="+x);
        }
        int x = 100;
        System.out.println("x="+x);
    }
}

构造块
定义:定义在类中的代码块

class Student{
    //定义在类中,不加任何修饰
	{
        System.out.println("student类的构造块");
    }
    public Student(){
        System.out.println("Student类的构造方法");
    }
}
public class Test{
    public static void main(String[] args){
        new Student();
        new Student();
    }
}

通过以上代码的执行结果可以看出:在对象产生时,构造块优先于构造方法执行,有几个对象产生就调用几次构造块。
在构造方法执行前完成一些属性的初始化操作,也可以进行简单地逻辑解释

静态代码块
定义:使用static修饰的代码块

根据所在的类不同分为以下:
在非主类中的静态代码块

class Student{
    //定义在类中,不加任何修饰
    {
        System.out.println("student类的构造块");
    }
    public Student(){
        System.out.println("Student类的构造方法");
    }
    //定义在非主类中的静态块
    static {
        System.out.println("Sudent类的静态块");
    }
}
public class Test{
    public static void main(String[] args){
        System.out.println("主方法开始");
        new Student();
        new Student();
        System.out.println("主方法结束");
    }
}

通过以上代码执行结果可以看出:静态库优先于构造块执行,并且屋里产生几个实例化对象静态块只执行一次

在主类中的静态块

public class Test{
    {
        System.out.println("主类的构造块");
    }
    public Test(){
        System.out.println("主类的构造方法");
    }
    static {
        System.out.println("主类的静态块");
    }
    public static void main(String[] args){
		System.out.println()
        new Test();
        new Test();
    }
}

由以上代码的运行结果可以看出:主类中的静态块优先于主方法执行

内部类的定义与使用
内部类的概念:所谓内部类就是在一个类的内部进行其他类结构的嵌套操作
 


class Person{
    private String msg = "Hello World";
    //定义一个内部类
    class Student{
        //内部类中定义一个普通方法
        public void print(){
            System.out.println(msg);
        }
    }
    //外部类中定义一个普通方法,调用内部类的print方法
    public void fun(){
        Student stu = new Student();//内部类对象
        stu.print();//内部类对象调用内部类提供的方法
    }
}
public class Test{
    public static void main(String[] args){
        //外部类对象
        Person per = new Person();
        //外部类对象调用外部类方法
        per.fun();
    }
}

上述代码就是内部类的简单定义实例,可以看出程序的结构有些乱,但是内部类可以方便地操作外部类的私有访问属性

将内部类拆分出来

class Person{
    private String msg = "Hello World";
    public String getMsg() {//设置get方法取得msg的属性
        return msg;
    }
    public void fun(){//Person类对象可以调用这个方法
        Student stu = new Student(this);//this表示当前对象
        stu.print();//调用Student类方法
    }
}
class Student{
    private Person per;
    public Student(Person per){
        this.per = per;
    }
    public void print(){
        System.out.println(per.getMsg());
    }
}
public class Test{
    public static void main(String[] args){
        Person per = new Person();//实例化Person对象
        per.fun();
    }
}

内部类的产生原因:
a.内部类方法可以访问该类定义所在作用于的数据,包括private修饰的私有数据
b.内部类可以对同一包下的其他类不可见
c.内部类可以实现Java单继承缺陷
d.当我们想要定义一个回调函数缺不行写太多代码的时候,可以使用匿名内部类实现

内部类实现Java多继承

class A{
    private String name = "A类的私有属性";
    public String getName() {
        return name;
    }
}
class B{
    private int age = 10;
    public int getAge() {
        return age;
    }
}
class Person{
    private class StudentA extends A{
        public String name(){
            return super.getName();
        }
    }
    private class StudentB extends B{
        public int age(){
            return super.getAge();
        }
    }
    public String name(){
        return new StudentA().name();
    }
    public int age(){
        return new StudentB().age();
    }
}
public class Test{
    public static void main(String[] args){
        Person per = new Person();
        System.out.println(per.name());
        System.out.println(per.age());
    }
}

内部类与外部类的关系
1.对于非静态内部类,内部类的创建依赖外部类的实例化对象,没有外部类实例化之前无法创建内部类
2.内部类是一个相对独立的个体,与外部类没有is-a关系
3.内部类可以直接访问外部类的元素(包含私有属性),外部必须通过内部类引用间接访问内部类元素

内部类直接访问外部类元素

class Outter{
    private String outName;
    private int outAge;

    class Inner{
        private int inAge;
        public Inner(){
            Outter.this.outName = "我是一个外部类";
            Outter.this.outAge = 20;
        }
        public void disPlay(){
            System.out.println(outName);
            System.out.println(outAge);
        }
    }
}
public class Test{
    public static void main(String[] args){
        Outter.Inner inner = new Outter().new Inner();
        inner.disPlay();
    }
}

外部类间接访问内部类元素

class Outter{
   public void display(){
       //外部类通过内部类引用来访问内部类元素
       Inner inner = new Inner();
       inner.display();
   }
   class Inner{
       public void display(){
           System.out.println("我是一个内部类");
       }
   }
}
public class Test{
    public static void main(String[] args){
        Outter out = new Outter();
        out.display();
    }
}


创建一个内部类对象
1.在外部类外部创建内部类对象语法:
外部类.内部类 内部类对象 = new 外部类().new 内部类();
Outter.Inner in = new Outter().new Inner();
2.在外部类内部创建内部类对象
内部类 内部类对象 = new 内部类();
Inner in = new Inner();

内部类的分类
在Java中内部类一般分为成员内部类、静态内部类、方法内部类、匿名内部类

成员内部类:
成员内部类不存在任何static变量和方法
成员内部类依附于外围类,只有先创建了外围类才能够创建内部类

静态内部类:
static关键字可以修饰成员变量、方法、代码块、还可以修饰内部类,使用static修饰的内部类称为静态内部类。
静态那我不来与非静态内部类最大的区别在于,非静态内部类在编译完成之后会隐含地保存一个引用,该引用指向创建它的外围类,但是静态内部类没有
所以,静态内部类的创建不需依赖外围类,可以直接创建;静态内部类不可以使用任何外围类的非static成员变量和方法。

静态内部类对象的创建语法:
外部类.内部类 内部类对象 = new 外部类.内部类()

class Outer{
    private static String msg = "Hello World";
    static class Inner{//定义一个静态内部类
        public void print(){
            System.out.println(msg);//调用外部类的msg属性
        }
    }
    public void fun(){
        Inner in = new Inner();//内部类对象
        in.print();//调用内部类方法
    }
}
public class Test {
    public static void main(String[] args){
        Outer.Inner in = new Outer.Inner();
        in.print();
    }
}

方法内部类()局部内部类
方法内部类定义在外部类方法中,局部内部类和成员内部类基本一致,只是他们的作用域不同,方法内部类只能在该方法中使用,出了该方法就会失效。
在解决某些比较复杂的问题时,想要创建一个类来辅助我们的解决方案,但又不希望这个类是公共可用的,所以就产生了局部内部类

a.局部内部类不允许使用权限修饰符(public、private、protected)
b.局部内部类对外完全隐藏,除了创建这个类的方法可以访问其他地方均不允许访问
c.局部内部类要想使用方法形参,该形参必须用final声明
 

class Outer{
    private int num;
    public void display(final int test){
        class Inner{//局部内部类
            private void fun(){
                num++;
                System.out.println(num);
                System.out.println(test);//局部内部类使用方法形参,test用final声明
            }
        }
        new Inner().fun();//在内部类的外部调用内部类方法
    }
}

public class Test {
    public static void main(String[] args){
        Outer out = new Outer();//创建外部类对象
        out.display(25);
    }
}


匿名内部类
概念:匿名内部类就是一个没有名字的内部类,所以它符合方法内部类的所有约束。
特征:
a.匿名内部类没有任何修饰符
b.匿名内部类必须继承一个抽象类或者一个接口
c.匿名内部类中不能存在任何静态成员或方法
d.匿名内部类没有构造方法,因为它没有类名
e.与局部内部类相同,匿名内部类也可以引用方法形参,该形参必须使用fianl声明


interface MyInterface{
    void test();
}
class Outer{
    private int num;
    public void display(final int num){
        //匿名内部类,实现MyInterface接口
        new MyInterface(){
            @Override
            public void test(){
                System.out.println("匿名内部类"+num);
            }
        }.test();
    }
}
public class Test {
    public static void main(String[] args){
        Outer out = new Outer();
        out.display(22);
    }
}

3.继承的定义与使用

面向对象的第二大特征:继承,继承的主要优势在于,在已有累的基础上继续进行功能的扩充
继承可以消除结构定义上的重复,避免大量重复代码的出现

继承的实现:class 子类(派生类) extends 父类(超类)

继承的基本实现:

class Person{//定义父类结构
    private String name;
    private int age;
	
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
}
class Student extends Person{//定义一个子类
}
public class Test {
    public static void main(String[] args){
        Student stu = new Student();
        stu.setName("张三");
        stu.setAge(22);
        System.out.println("姓名:"+stu.getName()+",年龄:"+stu.getAge());
    }
}

当子类发生了类继承关系之后,子类可以直接使用父类的操作,实现了代码的重用,同时子类可以进行功能上的扩充

class Student extends Person{//子类继承父类
    private String school;//子类扩充学校属性
    public String getSchool() {//扩充get,set方法
        return school;
    }
    public void setSchool(String school) {
        this.school = school;
    }
}
public class Test {
    public static void main(String[] args){
        Student stu = new Student();
        stu.setName("张三");
        stu.setAge(22);
        stu.setSchool("希望小学");
        System.out.println("学校:"+stu.getSchool()+",姓名:"+stu.getName()+",年龄:"+stu.getAge());
    }
}

继承的限制:子类对象在实例化之前一定会首先实例化父类对象,默认调用父类的构造方法后在调用子类构造方法进行初始化

class Person{//定义父类结构
    public Person(){
        System.out.println("Person类对象产生");
    }
}
class Student extends Person{//定义一个子类
   public Student(){
       System.out.println("Student类对象产生");
   }
}
public class Test {
    public static void main(String[] args) {
        Student stu = new Student();
        //Person类对象产生
        //Student类对象产生
    }
}


实际上在子类的构造方法中,隐含了一个super();
如果父类没有提供无参构造,那么必须使用super();明确表示要调用的父类构造方法
Java值允许单继承,不能多继承一个子类只能继承一个父类
可以使用多层继承的形式来实现多继承
class A{}
class B extends A{}//B类继承A类
class C extends B{}//C类继承B类

在进行继承时,子类会继承父类的所有结构(包含私有属性、构造方法、普通方法)
但是所有的非私有属性可以直接调用(属于显示继承),私有属性属于隐式继承,必须通过getter或setter方法来调用。
 

class Person{//定义父类结构
    private String name;

    public String getName() {//子类可调用方法
        return name;
    }
    public void setName(String name) {//子类可调用方法
        this.name = name;
    }
}
class Student extends Person{//定义一个子类
   public void fun(){
       System.out.println(this.getName());
   }
}
public class Test {
    public static void main(String[] args) {
        Student stu = new Student();
        stu.setName("张三");
        stu.fun();
    }
}

继承总结:
a.继承的目的是扩展已有的类,使代码重复利用
b.子类对象数理化之前,不管如何操作一定会先实例化父类
c.不可以多重继承,但是允许多层继承

4、覆写
覆写概念:如果子类定义了与父类完全相同的方法或熟悉属性时,这样的操作就是覆写

方法覆写:子类定义了与父类方法名称、参数类型及个数完全相同的方法。但是覆写时不能拥有比父类更为严格的访问控制权限
三种访问控制权限:private<default<public,就是说如果父类使用public 那么子类必须也使用public
 

class Person{//定义父类结构
    public void print(){
        System.out.println("父类的普通方法输出");
    }
}
class Student extends Person{//定义一个子类
    public void print(){
        System.out.println("子类的普通方法输出");
    }
}
public class Test {
    public static void main(String[] args) {
        new Student().print();//子类的普通方法输出
    }
}

在进行覆写操作时需要特别注意:当前使用的对象是通过哪个类new出来的
调用某个方法时,如果该方法已经被子类覆写,那么调用的一定是被付下过得方法

如果父类使用private修饰方法、子类使用public修饰方法,此时不存在方法覆写
父类方法用private定义,表示该方法只能被父类使用,子类不知道父类有这样的方法,更不可能覆写

class Person{
    public void fun(){
        this.print();
    }
//如果现在父类方法使用了private定义,那么就表示该方法只能被父类使用,子类无法使用。换言之,子类根本就不知道父类有这样的方法。
	private void print(){
        System.out.println("1.[Person]类的print方法");
    }
}
class Student extends Person{
    //这个时候该方法只是子类定义的新方法而已,并没有和父类的方法有任何关系。
    public void print(){
        System.out.println("2.[Student]类的print方法");
    }
}
public class Test{
    public static void main(String[] args) {
        new Student().fun();//1.[Person]类的print方法
    }
}

属性覆写
当子类定义了一个与父类属性美年广场完全相同的属性时,就称为属性覆写
 

lass Person{
    public String name = "小李";
}
class Student extends Person{
    public String name = "小花";
}
public class Test{
    public static void main(String[] args) {
       System.out.println(new Student().name);//小花
    }
}

super关键字的用法

使用super调用父类的同名方法

class Person{
    public String name = "小李";
    public void print(){
        System.out.println(name);
    }
}
class Student extends Person{
    public String name = "小花";
    public void print(){
        super.print();//调用父类方法
        System.out.println(name);
    }
}
public class Test{
    public static void main(String[] args) {
        new Student().print();//小李 小花
    }
}

使用super调用父类属性

class Person{
    public String name = "父类";
    public void print(){
        System.out.println(name);
    }
}
class Student extends Person{
    public String name = "子类";
    public void print(){
        System.out.println(super.name);//调用父类属性
        System.out.println(this.name);
    }
}
public class Test{
    public static void main(String[] args) {
        new Student().print();//父类 子类
    }
}


5.final关键字
在Java中final被称为终结器,可以使用final定义类、方法、属性

使用(String类就是final定义的)
final class A{}//不能有子类

使用final定义的方法不能被子类覆写
class A{
    public final void fun(){}
}

使用final定义的变量就成为了常量,常量必须在大亨们时赋值,并且不能被修改
关于final:
a.final关键字可以用于成员变量、本地变量、方法以及类
b.final成员变量必须在声明的时候初始化或者在构造器中初始化
public final int AGE = 18;
c.final变量不能再次赋值、本地变量必须在声明时赋值、final方法不能被覆写、final类不能被继承

6.多态性
多态的核心表现:
a.方法的多态性
    方法重载:同一个方法名称可以根据参数类型不同或个数不同调用不同的方法
    方法覆写:同一个父类非,可以根据资料不同实例化有不同的实现
b.对象的多态性:(方法覆写为前提)
    向上转型:父类 父类对象 = 子类实例(自动)
    向下转型:子类 子类对象 = (子类)父类实例(强制)
向上转型

class Person{
    public void print(){
        System.out.println("我是爸爸!");
    }
}
class Student extends Person{
    public void print(){
        System.out.println("我是儿子!");
    }
}
public class Test{
    public static void main(String[] args) {
        Person per = new Student(); //向上转型
        per.print();
    }
}

不管是否发生了向上转型,核心本质还是在于:你使用的是哪一个子类(new在哪里),而且调用的方法是否被子类所覆写了。

向下转型:
向下转型指的是将父类对象变为子类对象,当你需要子类扩充操作的时候就要采用向下转型

class Person{
    public void print(){
        System.out.println("1.我是爸爸!");
    }
}
class Student extends Person{
    public void print(){
        System.out.println("2.我是儿子!");
    }
    public void fun(){
        System.out.println("只有儿子有!");
    }
}
public class Test{
    public static void main(String[] args) {
        Person per = new Student();
        per.print();
        //这个时候父类能够调用的方法只能是本类定义好的方法
        //所以并没有Student类中的fun()方法,那么只能够进行向下转型处理
        Student stu = (Student) per;
        stu.fun();
    }
}


多态性总结:
  对象多态性的核心在于方法的覆写。
 通过对象的向上转型可以实现接收参数的统一,向下转型可以实现子类扩充方法的调用(一般不操作向下转型,有安全隐患)。
    两个没有关系的类对象是不能够进行转型的,一定会产生ClassCastException

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值