JavaSE高级复习-day01

  1. java中封装性的体现:
    o 首先是我们使用对象.属性=进行赋值,但是这样需要被属性的限定范围和数据类型限制,但是我们使用时往往是需要进行限定,为了避免使用对象.属性进行赋值,我们将属性设置为private修饰,类内提供public的set和get方法。
    o 对于单例模式,我们将构造器用private修饰。
    o 不能再类外调用类私有的成员。
    o 如果不希望类在包外被调用,可以将类设置为缺省的。

2.关于方法的重载
o 两同:同类同方法名 【和 方法修饰符、返回值类型 无关】
o 一不同:参数列表(形参个数不同、形参类型不同【形参顺序改变也算】)【和 形参的起名 无关】
get(String name ,int age) 和 get(int age, String name) 是重载
get(int sex ,int age) 和get(int age ,int sex)不是

3.对象创建的过程(JVM) 这里和回顾是因为复习到属性的赋值顺序:

  • 赋值顺序: 默认初始化(这里是为了能够编译通过) 、显式赋值 (在class中直接赋值,比如说:nation= “China”)、使用构造器赋值、 使用对象.属性赋值\使用对象.方法进行赋值。
    对象的创建过程: 看这个对象所属于的类是否加载、链接、初始化。
    如果加载过了,为对象在堆里分配空间: 如果堆是采用复制算法进行垃圾回收,那么内存是规整的,使用指 针碰撞法。
    如果采用的是标记-清除算法,则是不规整的,那么使用空闲列表 分配。
    处理线程的并发问题:我们可以在分配时使用TLAB。
    初始化分配到的内存空间,【默认初始化】,为了保证编译通过,在使用时不会报错。
    设置对象头。
    进行init初始化,构造器初始化。
    4.继承时,子类继承了父类的所有方法和属性,包括父类私有的方法和属性,只不过因为封装性,子类不能直接使用父类私有的结构。
    5.方法的重写
    权限修饰符 返回值类型 方法名(参数列表)throws 异常类型;
    在子类中重写父类的方法时:
    ① 方法名 参数列表相同
    ② 权限修饰不得小于父类,如果父类的方法时Private,不可以进行重写。
    ③ 返回值类型: 如果父类是void,子类必须是void
    如果父类是A类型,子类必须是A类或者是A类的子类
    如果父类是基本数据类型(比如:double),则子类重写的方法的返回值类型必须是相同的基本数据类型 (必须也是double)。
    ④ 子类抛出的异常不得小于父类抛出的异常。
    重载,是指允许存在多个同名方法,而这些方法的参数不同。编译器根据方法不同的参数表,对同名方法的名称做修饰。对于编 译器而言,这些同名方法就成了不同的方法。它们的调用地址在编译期就绑定了。Java的重载是可以包括父类和子类的, 即子类可以重载父类的同名不同参数的方法。
    所以:对于重载而言,在方法调用之前,编译器就已经确定了所要调用的方法,这称为“早绑定”或“静态绑定”;

而对于多态,只等到方法调用的那一刻,解释运行器才会确定所要调用的具体方法,这称为“晚绑定”或“动态绑定”。

6.子类在使用构造器创建对象时,会间接调用父类的的构造器,在间接调用父类的父类的构造器,直到调用object的构造器,就是因为这样才能知道父类中的结构,我们才可以使用。(这里我们需要明确一点是,虽然我们在创建子类的对象时调用父类及祖先类的构造器,这只是为了知道父类中有哪些结构,这里只创建了一个对象,就是new出来的那个。)

7.多态 的理解

  • 父类的引用指向子类的对象,试运行时行为

  • 虚拟方法调用【编译看左边、执行看右边】,在编译时,调用的是父类中声明的方法,在运行时,实际上执行的是子类中重写过得方法。 所以 Fu fu = new zi(), fu.num 只能取到父类中的属性值【因为属性是编译运行都看左边】; fu.method() 执行的是子类中重写过的方法,注意:只能调用父类中有的方法。执行时子类中重写过的。

  • instanceof 用于判断或是不是某一个类的对象,

  • 多态的转型
    向上转换 多态本身就是向上转型,
    向下转换 为什么要向下转型,因为使用多态 Fu fu = new zi(),内存中实际上是加载了子类特有的属性和方 法的,但是由于变量声明为父类类型,导致编译时,导致只能调用父类的属性和方法,虽然方法调 用时调用的是子类重写过的方法,但是只能调用父类中有的方法。有时候我们要是用调用子类的属 性和方法,我们就需要使用向下转型。
    使用强制类型转换,子类类型 变量名=(子类类型) 父类类型的变量;
    People p=new Stu();

    p.eat();

//调用特有的方法

Stu s=(Stu)p;

s.study();

用强转时,可能出现ClassCastException的异常。
② 为了避免在向下转型时出现ClassCastException的异常,我们在向下转型之前,先进行instanceof的判断,一旦返回 true,就进行向下转型。如果返回false,不进行向下转型。
面试题:
8.1 谈谈你对多态性的理解?
① 实现代码的通用性。
② Object类中定义的public boolean equals(Object obj){ }
JDBC:使用java程序操作(获取数据库连接、CRUD)数据库(MySQL、Oracle、DB2、SQL Server)
③ 抽象类、接口的使用肯定体现了多态性。(抽象类、接口不能实例化)
8.static关键词修饰
可以修饰属性、方法、代码块、内部类。 【随类的加载而加载,】

  • 修饰属性,类变量\静态变量,可以通过有类.属性、对象.属性进行调用,
    对于类变量,多个实例对象共享一个类变量,所以一个实例进行修改,会改变类变量,所有对象都会看见。
    对于实例变量,每一个实例对象一个,所以修改只能自己看到,不会影响其他对象。
  • 修饰方法,静态方法,可以通过类.方法、对象.方法 进行调用。
    静态方法只能使用静态成员。所以在静态方法中不能使用this 、 super。
  • 修饰代码块,
  • 修饰内部类,这里我们要了解一下单例模式。
    9.单例模式
    采取一定方法保证在软件系统中,一个类只存在一个实例。
    可以采用的方法 :
    饿汉式:
    私有化类的构造器,私有化创建对象,然后通过public方法来返回创建的对象。
class Student{
    
    
private Stuednt(){
    
    
}
private static Stuednt stu = new Student();
public static Stuednt getstu(){
    
    
     return stu;
}

之所以叫做饿汉式,是因为在类加载时就直接创建了类的实例,无论是否使用。
懒汉式:


```java
class Order{
    
    
	
	//1.私化类的构造器
	private Order(){
    
    
		
	}
	
	//2.声明当前类对象,没初始化
	//4.此对象也必须声明为static的
	private static Order instance = null;
	
	//3.声明public、static的返回当前类对象的方法
	public static Order getInstance(){
    
    
		
		if(instance == null){
    
    
			
			instance = new Order();
			
		}
		return instance;
	}
	
}

懒汉式和饿汉式对比:
饿汉式:加载时间长、线程安全
懒汉式:延迟了对象的创建,线程不安全
为了使用懒汉式,保证线程的并发的安全,我们使用方法:

10.接口
在jdk1.7之间,接口中只有:全局常量public static final xxx 和 抽象方法【这里常量为什要用static修饰,是因为接口不可以实例化,所以变量必须是随类的加载而加载,不然没用】
在jdk1.8之后,可以有静态方法和默认方法。//知识点1:接口中定义的静态方法,只能通过接口来调用。
  								 //知识点2:通过实现类的对象,可以调用接口中的默认方法。如果类中重写了方法
										  则调用的是重写过的方法。
类可以实现多个接口,接口可以实现多继承。
11.代理模式

代理模式的理解:
    代理通俗来说就是,我们需要一个代理人来执行一些操作,比如说黄牛买票,我们不用自己直接去和火车站进行交互,而是让黄牛进行交互。代理有:静态代理、动态代理。黄牛代理集就是静态代理。
    静态代理,实质就是自己手写(或者用工具生成)代理类,也就是在程序运行前就已经存在的编译好的代理类,如果说我们学要很多代理做不同的事情,我们就需要些不同代理类,需要都创建,这里面会有许多重复的代码,不是很方便简洁。
动态代理,是因为静态代理十分的不方便,动态代理可以在运行期间根据动态的创建代理类以及其实例来完成具体的功能。
为什么要使用代理模式呢?
代理模式可以有效将具体实现(买票过程)和调用方法(买票这)进行解耦,通过面向接口进行编码完全将具体实现(买票)隐藏在内部(黄牛)。我们还可以借助代理模式来增加一些功能,而不需要修改原有的代码,这样就符合开闭原则。
代理类和目标类之间通常存在关联关系,一个代理类的对象和一个目标类的对象关联,代理类的对象并不真正实现服务,而是通过调用目标类的对象的相关方法,来提供特定的服务。【代理对象应该具有和目标对象 相同的方法,即实现同一个接口或者继承同一个父类。代理类应该是对目标对象的增强,否则我们没必要使用代理,使用代理,也是为了能够不修改原代码来增加功能,为了满足开闭原则】比如在项目开发中没有加入缓冲、日志这些功能,后期需要加入时我们可以使用代理来实现,这样既符合开闭原则,没有直接去修改封装好的目标类,也满足了要求。

静态代理实现: 
    jdk代理都是借助接口实现的,我们需要先定义一个借口,然后创建具体实现类来实现这个接口,然后再创建一个同样实现接口的代理类。不同之点在于,实现类的方法是需要将接口中的抽象方法实现,而代理类中方法只要调用具体类中的对应方法即可,这样我们需要在使用接口中的某个方法功能时直接调用代理类的方法即可,因为我们调用代理类中的方法,这个方法是调用的是具体实现类中对应的方法,也就是接口中方法的具体实现。
    自己的话总结就是,定义接口,定义实现类实现接口,定义代理类,代理类中的方法不用实现,只用调用实现类中相应的方法即可,这样我们在调用接口的方法是不用调用接口,我们调用代理类的方法,代理类中的方法会去调用实现类中的方法。
   

```java
抽象主题(接口):
package com.frank.test;
public interface Movie {
    void play();
} 
被代理(实现类):
package com.frank.test;
public class RealMovie implements Movie {
    @Override
    public void play() {
        // TODO Auto-generated method stub
        System.out.println("您正在观看电影 《肖申克的救赎》");
    }
}
 代理类:
package com.frank.test;
public class Cinema implements Movie {
    RealMovie movie;
    public Cinema(RealMovie movie) {
        super();
        this.movie = movie;
    }

    @Override
    public void play() {
        guanggao(true);    // 代理类的增强处理
        movie.play();     // 代理类把具体业务委托给目标类,并没有直接实现
        guanggao(false);    // 代理类的增强处理
    }

    public void guanggao(boolean isStart){
        if ( isStart ) {
            System.out.println("电影马上开始了,爆米花、可乐、口香糖9.8折,快来买啊!");
        } else {
            System.out.println("电影马上结束了,爆米花、可乐、口香糖9.8折,买回家吃吧!");
        }
    }
}
 客户端:
package com.frank.test;
public class ProxyTest {
    public static void main(String[] args) {
        RealMovie realmovie = new RealMovie();
        Movie movie = new Cinema(realmovie);
        movie.play();
    }
}/** Output
        电影马上开始了,爆米花、可乐、口香糖9.8折,快来买啊!
        您正在观看电影 《肖申克的救赎》
        电影马上结束了,爆米花、可乐、口香糖9.8折,买回家吃吧!
 **/

动态代理实现:
动态代理可以在程序运行期间根据需要动态建立创建代理类及其实例来完成具体的功能。

接口:
package cn.inter;
public interface Subject {
    
    
    public void doSomething();
}
   被代理(实现类):
package cn.impl;
import cn.inter.Subject;

public class RealSubject implements Subject {
    
    
    public void doSomething() {
    
    
        System.out.println("call doSomething()");
    }
}
     代理类和客户端:
在动态代理中,因为是根据需要进行动态创建代理类及其实例,代理类和其实例是程序自动生成的,因此我们不需要手动去创建代理类。在Java的动态代理机制中,InvocationHandler(Interface)接口和Proxy(Class)类是实现我们动态代理所必须用到的。事实上,Proxy是使用InvocationHandler对象生成具体的代理对象的,每个代理的实例都有一个与之关联的InvocationHandler,实现类,如果代理的方法被调用,那么代理便会通知和转发给内部的 InvocationHandler 实现类,由它调用invoke()去处理。
package cn.handler;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
 * Title: InvocationHandler 的实现 
 * Description: 每个代理的实例都有一个与之关联的 InvocationHandler
 * 实现类,如果代理的方法被调用,那么代理便会通知和转发给内部的 InvocationHandler 实现类,由它调用invoke()去处理。
 * 
 
public class ProxyHandler implements InvocationHandler {
    private Object proxied;   // 被代理对象
    public ProxyHandler(Object proxied) {
        this.proxied = proxied;
    }
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        // 在转调具体目标对象之前,可以执行一些功能处理
        System.out.println("前置增强处理: yoyoyo...");

        // 转调具体目标对象的方法(三要素:实例对象 + 实例方法 + 实例方法的参数)
        Object obj = method.invoke(proxied, args);

        // 在转调具体目标对象之后,可以执行一些功能处理
        System.out.println("后置增强处理:hahaha...");

        return obj;
    }
}

客户端:
package cn.client;

import java.lang.reflect.Proxy;

import cn.handler.ProxyHandler;
import cn.impl.RealSubject;
import cn.inter.Subject;

public class Test {
    public static void main(String args[]) {

        // 真实对象real
        Subject real = new RealSubject();

        // 生成real的代理对象
        Subject proxySubject = (Subject) Proxy.newProxyInstance(
                Subject.class.getClassLoader(), new Class[] { Subject.class },
                new ProxyHandler(real));

        proxySubject.doSomething();
        System.out.println("代理对象的类型 : " + proxySubject.getClass().getName());
        System.out.println("代理对象所在类的父类型 : " + proxySubject.getClass().getGenericSuperclass());
    }
}/** Output
        前置增强处理: yoyoyo...
        call doSomething()
        后置增强处理:hahaha...
        代理对象的类型 : com.sun.proxy.$Proxy0
        代理对象所在类的父类型 : class java.lang.reflect.Proxy
 **/

12.内部类
内部类就是在类内部进行定义的类,可以是成员内部类【可以是静态也可以是非静态】,也可以是局部内部类【在方法体、代码块、构造器中】。举一个生动形象的例子,在person类中,我们需要心脏,我们可以定一个心脏内部类,这个类在外面也不能单独使用,所以就定义成内部类。
内部类作为成员,可以调用外部类的结构。可以被static修饰、可以四种权限修饰。
内部类作为类,可以有构造器、方法、属性,可以被继承、可以被abstract修饰。

猜你喜欢

转载自blog.csdn.net/qq_45204129/article/details/115919822
今日推荐