面向对象编程--------JavaSE

面试题 1,谈谈this和super的区别?

super时表示当前父类对象的引用

1)super(),调用父类的构造方法,帮助父类进行构造,必须放到第一行

2)super.data;访问父类的属性

3)super.func(),访问父类的方法

this表示当前对象的引用

1)this()调用自己的构造方法

2)this.data调用自己的属性

3)this.func(),调用当前对象的方法,只能在构造方法里面调用,只能放在第一行,一般这是有两个构造方法,来进行使用;

面试题2:说说重载和重写的区别:

运行时绑定:父类引用引用子类对象,同时通过父类引用调用同名的覆盖方法,此时就会发生运行时绑定

重载:方法名相同,参数列表不同(参数的类型加上个数),返回值不做要求,必须在同一个类中

重写:1)需要重写的方法,是不可以被final修饰的,被final修饰之后,他是密封方法,不可以进行修改

2)被重写的方法,他的访问修饰限定符一定不可以是私有的;

3)被重写的方法子类的访问权限限定一定要大于等于父类的访问权限限定

private<default<protected<public

4)被static修饰的静态方法是不可以被重写的

方法名称相同,返回值类型相同,参数列表(参数的个数以及类型)相同,必须在不同的类上,要有继承关系

面试题三:抽象类和接口的区别,抽象类和普通类的区别

面试题四:final关键字的作用

1)final修饰的变量是常量,不可以进行修改

2)抽象类和抽象方法,一定是不可以被final所修饰的,被final修饰的类,是不可以被继承的,被final修饰的方法,是不可以被重写的,就不能发生运行时绑定;

3)final修饰的引用:该引用只能指向1个对象,并且它只能永远指向该对象,并且无法指向其他对象。

面试题5:static 关键字的用法

1.包的介绍

package:包,类所在的包,包是一组类的集合,可以防止类名冲突,import static可以导入一些静态方法,import可以导入一个具体的包,这是错的,值可以导入包中的一组类或者多组类;

import:引入,指引入了类所需要的类

import是导入包,以区别于同个名称的但是属于不通包的类;

在文件上方有一个字段是package,是将当前类导入到包中,等以后要使用的时候,可以使用import将其导入

正常情况下,有一个叫做java.util底下的包,他里面有一个package的字段,意思是把当前的类导入包中,以便后续的程序可以使用import来到如使用这个包里面的方法;

import java.util.Arrays这个意思就是导入java.util中的Arrays类

java.util.*,代表导入包中的所有的类,java在这个地方处理的时候,用谁就自动倒谁;

在C语言里面,是全部进行导入,一个类,在不同的包中有不同的内容

——————————————————————————————————

2.包的访问权限控制

包是为了保证类的唯一性,包名必须是小写字母包的访问权限控制:当你的成员变量,不加任何的访问修饰限定符的时候

1)不加任何的字段作用,相当于是default:默认是包访问权限:只能在同一个包中的相同类或者同一个包中的不同类使用和进行访问

只在包中使用 int a=10,这个变量不可以在包外使用,也就是说,这个变量只能在同一个包中的不同类进行使用和访问,例如如果是一个类,class Test{},他的前面也没有加任何的访问修饰限定符,所以他也只能在一个包中进行访问;只能在包内new,不可以在包外new;

2)加上public之后,就可以在包外进行访问了,同时在包内也可以使用,任何地方都可以进行访问

3)private:只可以在类中进行使用,在同一个包中的同一个类;

4)defalut:默认为在同一个包内可以访问,包外不能访问

只可以在同一个包中进行访问,同一个包中的同一个类,同一个包中的不同类都可以进行访问,别管是子类还是非子类,只要出现了不同的包中,就不可以进行访问;

5)protected:它主要是体现在继承上面的,同一个包中的同一个类,同一个包中的不同类,以及不同包中的子类都可以进行访问;如果有不同包的类想调用它,只能通过访问重新定义它的子类来访问。

——————————————————————————————————————————

3.类和对象

1)C语言是面向过程的,关注的是过程,分析出解决问题的步骤,通过函数调用来进行逐步解决问题
2)但是Java是面向对象的,关注的是对象,将同一个事情拆分成不同的对象,靠对象之间来相互进行完成
3)面向过程注重的是过程,也就是参与过程中所有所涉及到的行为,就是功能;
4)面向对象:打开冰箱,储存,关闭都是对冰箱进行的操作,这是对冰箱的一种行为;但是冰箱就是一个对象,所以只要冰箱所具备的功能,就都需要被定义到冰箱中;
5)面向对象是思考问题的一种方式,是一种思想,比如概念与实例,理论与实践,名和实等;
6)类就是一类对象的统称,对象就是这一类具体化的一个实例;

在方法外定义的变量,我们称之为字段,属性,或者成员变量,其中的成员变量分为普通成员变量和静态成员变量

class Student{
    public String name;
    public int age;//这是一个普通成员变量
    public static int count=9;//这是一个静态成员变量
    public void run()
    {
        System.out.println(1);
    }
public static void start()
    {
        System.out.println(2);
    }
}
new Student()在堆上,但是指向new Student()的实例(引用)在栈上;

类是由字段和方法构成的,静态成员变量不像普通成员变量,不属于对象,而是属于类,类名.静态成员变量

实例成员方法和静态成员方法

static 关键字

1)被static修饰的成员变量和成员方法独立于该类的任何对象,他是和类紧紧联系在一起的
被类所有的实例所共享,他是永远在方法区的,它不属于类的对象,但是属于类;
2)这也就是说不管创建多少对象,static修饰的变量只占有一块内存。

3)静态方法只能访问静态方法和静态字段,实例成员方法只能调用实例成员字段,main方法是一个静态成员方法,她所调用的函数必须用static修饰,final修饰的成员变量在堆中,局部变量在栈中

4)java中 被static修饰的 class 都是 内部类,static class 是可以被继承的,但是被static修饰的方法是不可以重写的

静态成员变量:
声明为static关键词修饰的变量叫做静态成员变量,也叫全局变量。
静态成员变量的访问方式:
直接通过类名调用类的静态成员变量:
类名.静态成员变量名

静态成员方法:
声明为static关键词修饰的方法叫做静态成员方法。例如:作为Java应用程序入口的main成员方法就是一个静态成员方法。
静态成员变量方法的访问方式:
通过类名调用类的静态成员方法:

类名.静态成员方法名(成员方法调用参数列表)
在静态方法里只能直接调用同类中其他的静态成员(包括变量和方法),而不能直接访问类中的非静态成员。


引用是不一定在栈上面的

class Person{
    public String name;
    public int age;//这是一个普通成员变量
}
 class yyy{
    Person lijiawei=new Person();
     public static void main(String[] args) {

     }
 }

 

—————————————————————————————————————————— 

4.面向OP语言的三大特征

1.封装的好处:不必要的公开里面的数据成员或方法,使用private进行修饰,为了更安全,它会提供公有的方法,对于类的调用者来说,不需要知道具体的实现细节,只需要调用这些共有的方法即可,降低了代码的管理复杂度

this:代表当前对象的引用

一:构造方法:他的方法名称和类名是相同的,而且没有返回值

1)每一个类中至少存在一个构造方法,当你没有提供构造方法的时候,编译器会自动提供一个不带有参数的构造方法

2)当你提供了构造方法,编译器就不会再生成构造方法了

3)构造方法之间构成重载

二:面试题:一个对象的产生(new的过程),要经过几步?

1)为对象分配合适的内存空间

2)调用合适的构造方法

三:this的用法:

1)this()调用自己的构造方法

2)this.data调用自己的属性

3)this.func(),调用当前对象的方法,只能在构造方法里面调用,只能放在第一行,一般这是有两个构造方法,来进行使用;

——————————————————————————————————————————

四:代码块:

1)实例代码块,使用一个大括号,里面可以放一些语句和访问一些成员变量

2)静态代码块:static{ 里面放一些字段和方法};

静态代码块的执行顺序>实例代码块的执行顺序

package 李佳伟;
import javax.swing.*;
import java.security.PrivateKey;
import java.util.Scanner;
import java.util.Arrays;
import java.util.Scanner;
class Person//一个类
{ public int age;
    public static int count=0;
    public Person()//无返回值类型声明,且必须与类名相同
    {
    System.out.println("我是构建方法");
    }
    {
        System.out.println("我是示例代码块");

    }
    static{
count=99;//如果都是静态的,则初始化前看一看被定义的先后顺序
//this .age=18;不行因为静态代码区不能访问实例变量
且this表示当前对象的引用
        System.out.println("我是静态代码块");
    }

}
public  class HelloWorld {
    public static void main(String[] argv)
    {
Person lijiawei=new Person();//lijiawei就是一个对象,而且一个类可以面向多个对象
    }
//如果在定义一个李佳伟2的类,那么静态区的内容不会被二次打印,因为他只会执行一次,并且会最早被执行
    }
//静态代码块>实例代码块>构造方法

1)所以我们得出结论,静态代码块无论生成多少个对象,就只会执行一次,况且是最先执行的

2)静态代码块执行完毕后,实例代码块(构造快)再去执行,最后是构造方法执行

class Person{
    public static int count=0;
    static{
        System.out.println("我是静态代码块");
    }
    public static void run()
    {
        System.out.println("我是run方法");
    }
}
   System.out.println(Person.count);
//最终打印的结果是我是静态代码块,0
对于toString方法来说,在调用println方法的时候会被自动调用

---------------------------------------------------------------------------------------------

2.继承:

父类,基类,超类,子类派生类,会对代码进行重复使用

语法规则:

1)java中只能继承一个类,是单继承,不能继承两个类以上的类

2)子类会继承父类的所有public字段和方法,继承所有除构造方法之外的,private修饰的字段是可以继承于子类的,但是不可以访问;

3)子类在进行构造的同时,要先帮助父类进行构造,当我们在进行new 子类()的时候,肯定要调用子类的构造方法,我们还要帮助父类进行构造,怎么帮助他进行构造呢?这是就要用到super字段;

4)子类继承了出构造方法的所有方法,但是如果父类的字段中出现了有private修饰的字段,此时子类就无法访问了,那么我们如何既在子类中可以访问父类用private修饰的字段,又可以还不改变它封装的本质呢?这是就要用到protected关键字

5)在子类实例中,也是可以包含父类的实例,可以通过super关键字来获取父类实例的引用;

package PACKAGE;
class father{
    public int id=90;
    public String name;
    public int age;
    public father(String name,int age){
        this.name=name;
        this.age=age;
    }
    public void run()
    {
        System.out.println("我是父亲的run方法");
    }
}
class child extends father{
    public child(String name,int age){
        super(name,age);
        super.run();
        System.out.println(super.id);
    }
}

public class Servlet {
    public static void main(String[] args) {
        child t1=new child("李佳伟",23);
    }
}
打印结果:
1)我是父类的构造方法
2)90

final关键字:

1)常量,只能被初始化一次,后续就不可以在修改了

2)被final修饰过的类叫做密封类,他不可以在被继承了;

3)final修饰方法,不可以重写

——————————————————————————————————————————

3.多态:

什么是多态:让类的调用者甚至都不需知道这个类的类型,只需要知道这个对象有哪些方法即可

降低圈复杂度,不需要使用大量的if-else语句,扩展能力极强

1)向上转型:通过父类引用来指定子类对象,进行向上转型之后,通过父类的引用,只能访问父类自己的方法和字段属性,只能访问自己特有的;

发生向上转型的时机:1)直接赋值

2)函数参数是子类引用,接收参数是父类引用

3)返回值,   Animal func(){    return cat;}

2)向下转型:Cat cat=(Cat)new Animal;子类引用引用父类对象

向下转型非常不安全

Animal animal=new Cat();

//这时会出现类型转换异常,此时的Animal已经是cat类型了
要想避免这种情况
if(Animal instance of Bird)
{
Brid brid=(Bird)new Animal();
}

发生多态的条件

1)通过父类引用引用子类对象

2)父类与子类有同名的覆盖方法

3)通过父类引用调用重写的重名方法之后

​​​​​​​常见用法:1)使用java中的集合类,例如说List<String> list=new ArrayList();
2)多线程情况下,继承Thread,重写runnable,都必须提供run方法,JVM内部调用父类的run方法,从而执行到用户自己定义的run方法
3)DataSource dataSource=new mysqlDataSource();
4)再尝试进行数据库链接的时候,会用到向下转型
((MysqlDataSource) datasource).setURL(url);
((MysqlDataSource) datasource).setUser(username);
((MysqlDataSource) datasource).setPassword(password);

———————————————————————————————————————

4.抽象类和接口

抽象方法:如果一个方法被abstract修饰,它里面连一条语句都没有,那么这个方法叫做抽象方法,可以没有具体的实现

1)抽象类:包含抽象方法的类,就叫做抽象类,只是多了一个抽象方法;

  abstract public void draw();
    public int age=90;
    public static String name;
    public void run()
    {
        System.out.println("我是一个抽象类,里面也可以包含着普通法方法");
    }

1)抽象类不可以被实例化,不可以new

2)类中的成员可以有和其它类相同的public字段和方法,也就是说可以包括其他的非抽象方法,这个非抽象方法和普通方法的规则都是一样的,可以被重写,也可以被子类直接调用

3)抽象类就是为了被继承的,如果一个类继承了抽象类,那么这个类必须重写抽象类中的抽象方法,如果不想重写,那么还可以是他在被一个类继承,那么在这个类中,必须重写抽象类里面的所有抽象方法,出来混,迟早都是要还的;

4)抽象类和抽象方法,一定是不可以被final所修饰的,被final修饰的类,是不可以被继承的,被final修饰的方法,是不可以被重写的,就不能发生运行时绑定,抽象方法还不可以被private修饰;

2)接口:接口是抽象类的更进一步的抽象,抽象类中还可以包含非抽象方法和字段,但是接口中的包含的方法都是抽象方法,字段只能包含静态常量

1)接口中的方法,都是抽象方法,可以有具体的实现方法(JDK1.8可以实现,里面可以有default字段)

2)接口中的成员变量,默认是常量,在抽象类中,什么样的成员变量都可以被定义,但在接口中全部是常量,public static final,成员方法默认是public abstarct;这些东西都不用写

3)接口是不可以被实例化的

4)接口和类之间用implements,一个类中实现了接口,一定要重写接口里面的抽象方法

5)它的存在就是为了解决java中的单继承问题,在java中,可以实现多个接口,仍然可以实现向上转型,一个类可以继承普通类或者抽象类,同时还可以实现多个接口,先是extends,还有implements;此时在这个类中,要重写帮助父类进行构造,还要重写抽象类和接口中的抽象方法;

6)在进行比较时,自定义类型要想比较,必须实现Compartor接口,重写compareTo方法

7)接口中的方法可以有具体的实现,只能通过default方法来修饰这个方法

8)在接口中,可以有static的方法,除此之外里面的方法都是public的

9)当一个类实现一个接口之后,重写这个接口里面的方法之后,这个方法前面必须加public

10)一个类只能通过关键字extends继承一个抽象类或者普通类,但是去可以实现多个接口,用,来进行隔开

11)接口与接口之间可以使用继承

interface student{
    public void run();
}
interface teacher extends student{
    public void start();
}

5.自定义类型的比较:

1)继承comparable接口,重写CompareTo方法,里面加上泛型参数,泛型参数里面加上要比较的类型,这种写法,对类的侵入性比较强

 static class Student implements Comparable<Student>
    {
        public String name;
        public int age;
        public Double score;

        public Student(String name, int age,Double score) {
            this.name = name;
            this.age = age;
            this.score=score;
        }
        @Override
        public int compareTo(Student o) {//谁调用CompareTo谁就是this
            if(this.age>o.age) return 1;//在这里也可以同构比较年龄
            else if(this.age==o.age) return 0;
            else{
                return -1;
            }
        }

        @Override
        public String toString() {
            return "Student{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    ", score=" + score +
                    '}';
        }
    }

    public static void main(String[] args) {
        Student student1=new Student("李佳伟",15,23.9);
        Student student2=new Student("李佳鑫",34,89.9);
        Student student3=new Student("周云刚",89,10.9);
        Student[] arr1={student1,student2,student3};
        Arrays.sort(arr1);
        System.out.println(Arrays.toString(arr1));
        if(student1.compareTo(student2)>0)
        {
            System.out.println(1);
        }

2)定义一个新的类,让他继承Comparator接口,里面要有一个泛型参数,放比较的类型,之后在我们的main方法里面直接可以new一个比较器,里面的参数就是我们想要比较的类型

  static class AgeComparator implements Comparator<Student>
    {


        public int compare(Student o1, Student o2) {
            return o1.age- o2.age;
        }
    }
    static class Student {
        public String name;
        public int age;
        public Double score;

        public Student(String name, int age, Double score) {
            this.name = name;
            this.age = age;
            this.score = score;
        }

        @Override
        public String toString() {
            return "Student{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    ", score=" + score +
                    '}';
        }

    }
        public static void main(String[] args) {
            Student student1 = new Student("李佳伟", 15, 23.9);
            Student student2 = new Student("李佳鑫", 4, 89.9);
            Student student3 = new Student("周云刚", 89, 10.9);
            Student[] arr1 = {student1, student2, student3};
            Arrays.sort(arr1,new AgeComparator());
            System.out.println(Arrays.toString(arr1));
            //或者也可以这么进行比较
            AgeComparator ageComparator=new AgeComparator();
           if(ageComparator.compare(student1,student2)>0)
           {
               System.out.println(1);
           }


        }

3) 实现克隆接口

想要克隆自定义类型,就要实现克隆接口public interface Cloneable(){};空接口也叫作标记接口,其实一个类实现了这个接口,就标记这个类是可以进行克隆的;这里面是没有抽象方法的

class Student implements Cloneable
{
    String name;
//实现这个接口要重写克隆方法

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

public class Tomact {
    public static void main(String[] args) throws CloneNotSupportedException {
        Student student1=new Student();
        Student student2= (Student) student1.clone();
        System.out.println(student1.name);
        System.out.println(student2.name);
        student2.name="方法";
        System.out.println(student1.name);
        System.out.println(student2.name);

    }
}
新创建了一个对象

重写克隆方法,这是Object里面的方法

class Money{
    public double m=100.5;
        }
class Student implements Cloneable
{
    String name;
//实现这个接口要重写克隆方法
Money money=new Money();
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

public class Tomact {
    public static void main(String[] args) throws CloneNotSupportedException {
        Student student1=new Student();
        Student student2= (Student) student1.clone();
        System.out.println(student1.money.m);
        System.out.println(student2.money.m);
        student2.money.m=199;
        System.out.println(student1.money.m);
        System.out.println(student2.money.m);


    }
}

下面我们来实现一个真正意义上的深拷贝: 

class Money implements Cloneable{
    public double m=100.5;

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return  super.clone();

    }
}
class Student implements Cloneable
{
    String name;
    //实现这个接口要重写克隆方法
    Money money=new Money();
    @Override
    protected Object clone() throws CloneNotSupportedException {

        //  return super.clone();正常情况下,Person的克隆是在这里面执行
       // Student s=(Student) super.clone();
      //  return s;
        //1克隆Person
        Student s= (Student) super.clone();
        //2克隆当前的Money对象
        s.money= (Money) this.money.clone();
        return s;


        // 由于下面要进行Money的克隆
    }
}

public class Tomact {
    public static void main(String[] args) throws CloneNotSupportedException {
        Student student1=new Student();
        Student student2= (Student) student1.clone();
        System.out.println(student1.money.m);
        System.out.println(student2.money.m);
        student2.money.m=199;
        System.out.println(student1.money.m);
        System.out.println(student2.money.m);
        //这里面只是克隆了一个person,我们要想实现深拷贝,就要把money这个对象也克隆一份


    }
}

猜你喜欢

转载自blog.csdn.net/weixin_61518137/article/details/124673932