【Java】基础_16_hashcode/哈希表原理,Map/内部接口,断点调试,设计模式
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了【Java】基础_16_hashcode/哈希表原理,Map/内部接口,断点调试,设计模式,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含26335字,纯文字阅读大概需要38分钟。
内容图文
文章目录
- 1.Object类的hashcode方法
- 2.String类的hashcode方法
- 3.哈希表(HashSet)原理
- 4.HashSet元素重复原理应用
- 5.linkedHashset和Hashset区别
- 6.Map
- 7.内部接口
- 8.HashMap原理分析
- 9.统计字符出现个数
- 10.断点调试
- 11.模板
- 12.单例
- 13.工厂
- 14.代理
1.Object类的hashcode方法
package com.itheima03.hash;
/*
* HashCode : 哈希码
* 1. Object类有一个方法:
* int hashCode() : 返回该对象的哈希码值。
* 1. 原理: 将对象的真正的内存地址(明文) 进行 哈希算法 加密之后产生的 哈希码值(密文)
* 2. 加密 :
* 明文 : 大家都看的懂东西 I love you
* 密文 : 明文经过加密算法变成密文 J mpwf zpv
* 加密算法: 数学 (凯撒加密: 字母按字母表右移动一位)
* 破解 : 频率分析法 (e i -> d h),截获大量数据进行大数据分析e,i出现频率最高,密文中出现最多的是d,h
*
* 哈希算法: 公开
* 基本保证 一个明文 -> 一个密文 不同明文不同的密文
* 告诉你算法,告诉你密文, 算不出明文
*
* 3. 源码: public native int hashCode(); 本地方法
* native(本地关键字) 修饰的方法没有java方法体 (方法实现在JVM底层, 用C语言写的)
* 返回值 int (43亿不到的可能)
*
* 对象的真正的内存地址(无限种)->哈希码 (43亿不到的可能)。极端 : 多个明文 -> 同一密文 (哈希碰撞)
*/
public class HashcodeDemo {
public static void main(String[] args) {
Person p = new Person();
System.out.println(p); //com.itheima03.hash.Person@14ae5a5
// return getClass().getName() + "@" + Integer.toHexString(hashCode());
System.out.println(p.toString());//com.itheima03.hash.Person@14ae5a5
// 上面两个打印结果都一样
// 内存地址: 16进制哈希码值14ae5a5 和下面10进制相等
System.out.println(p.hashCode()); // 10进制: 21685669
}
}
class Person{
}
2.String类的hashcode方法
String s1 = “abc”,如下h就是hash值,b是98,c是99
package com.itheima03.hash;
// String类重写了Object的hashcode方法 (31算法)
public class StringHashCodeDemo {
public static void main(String[] args) {
String s1 = "abc";
String s2 = "acD";
String s3 = "重地";
String s4 = "通话";
System.out.println(s1.hashCode());//96354
System.out.println(s2.hashCode());//96354 //和上面哈希碰撞
System.out.println(s3.hashCode()); //1179395
System.out.println(s4.hashCode()); //1179395
}
}
3.哈希表(HashSet)原理
hashcode为HashSet(HashSet底层数据结构是hash表)做铺垫。问题:HashSet如何判定这个元素是否跟已存在的元素是重复的?Set是不存重复元素的。
HashSet是效率最高的set,同一链表hashcode一样,但是链表如果太长查询慢,所以假如同一hash值碰撞了8次,链表重构为红黑树。
%16因为数组长度为16。16的容量为什么到16*0.75=12就扩容了?rehash这段时间内,16没满,我还有的用。如果rehash非常快就不用提前
4.HashSet元素重复原理应用
package com.itheima02.set;
import java.util.HashSet;
import java.util.Objects;
/*
* HashSet: 判定重复元素
* 1. 地址是否相同,如果不同进行下面2
* 2. hashcode是否相等和equals是否为true
*
* Object: 1. hashcode
* 内存地址加密得到密文hash值(不同明文产生不同密文,刘亦菲两个内存地址不一样,密文hash值基本不会相同,万一碰撞了,还有下面2进行保障)
* 2. equals
* == 比较真正内存地址
*
* 需求: 两个对象就算地址不同, 但是所有属性一一相同, 就认为是同一元素
* 解决: 重写hashcode和equals方法 -> 类中的所有属性
*/
public class HashSetDemo02 {
public static void main(String[] args) {
HashSet<Person> set = new HashSet<>();
set.add(new Person("高圆圆",18));
set.add(new Person("刘亦菲",19));
set.add(new Person("刘亦菲",19));//Person类继承Object类,new新地址
System.out.println(set);
}
}
class Person{
String name;
int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public boolean equals(Object o) { //alt+insert选equals()and hashCode()
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false; //每个属性一一比对
Person person = (Person) o;
return age == person.age &&
Objects.equals(name, person.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age); //工具类Objects.java中hash方法中hashCode方法就是31算法,也是逐一遍历
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
没有重写Person类的hashcode和equals方法
如下重写…如上
5.linkedHashset和Hashset区别
package com.itheima00.question;
import java.util.HashSet;
import java.util.LinkedHashSet;
/*
* Set: 不保证存入和取出顺序一致
* HashSet : 无序
* LinkedHashSet : 多个另一个链表, 来记录存入的顺序,有序但效率低(少用)
*/
public class Demo01 {
public static void main(String[] args) {
HashSet<String> set = new LinkedHashSet<>(); //向上转型
set.add("张三");
set.add("李四");
set.add("王五");
set.add("马六");
System.out.println(set); //打印出有序的,LinkedHashSet不同于HashSet
}
}
package com.itheima00.question;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class Demo02 {
public static void main(String[] args) {
Collection<String> coll = new ArrayList<String>();//Collection是接口
coll.add("张三");
coll.add("张三2");
coll.add("张三3");
// Iterator接口类型 变量 = 其实现类对象 (多态的向上转型)
/* Iterator<String> it = coll.iterator();//执行子类ArrayList重写的iterator()
while(it.hasNext()){
String name = it.next();
System.out.println(name);
}*/
// Iterator<String> it = coll.iterator();
// while(coll.iterator().hasNext()){ //不能这样链式编程,如下图
// String name = coll.iterator().next();
// System.out.println(name);
// }
}
public static void method01(){
MyClass mc = new MyClass();
A a = mc.test(); //右边返回必然是A接口实现类对象即向上转型,不需要new
//上行等同于Iterator<String> it = coll.iterator();
A a2 = new A() { //java中对象不一定看到new才放心
@Override
public void show() {
}
} ;
}
}
interface A{
void show();
}
class MyClass{
public A test(){ //返回A
// A a = new A(){}; //匿名内部类
// return a;
return new A() { //下面等同于上面两行,return A接口的子类对象
@Override
public void show() {
}
};
}
}
6.Map
Map和Collection是并列关系
package com.itheima01.map;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
/*
Map中的方法
1. Map<K,V> <泛型>: K 表示作为键的类型,V表示值的类型
2. put: 存储键值对
1. 键值对存储到集合中 V put (K,V)
2. 如果存储了相同的键,覆盖原有的值
3. 返回值:一般返回null,如果存储了重复的键,返回被覆盖之前的值
3. get:通过键,取出键对应的值
1. V get(K),传递键,返回对应的值
2. 如果集合中没有这个键,返回null
4. remove:移除键值对
1. V remove(K),传递键,移除这个键值对
2. 返回值:移除之前的值(无此键,则返回null)
5. keySet:将集合中所有的键,存储到Set集合中
6. entrySet: 获取到Map集合中所有的键值对存入Set接中
7. size:获取map集合的大小
* Map:
* 1. key不可以重复
* 2. value可以重复
* 如果key存在,那么新value覆盖旧value
*/
public class MapDemo {
public static void main(String[] args) {
Map<Integer,String> map = new HashMap<>();
map.put(1,"张三");
map.put(2,"李四");
map.put(3,"王五");
map.put(4,"王五");
map.put(3,"马六"); //覆盖王五
System.out.println(map);//{1=张三,2=李四,3=马六,4=王五}
//从key获取value
String name = map.get(3);
System.out.println(name);//马六
//根据key删除key-value
map.remove(3);
System.out.println(map);
System.out.println(map.size()); //3,几个k
}
}
如下key不可重复,所以放到set集合。如下两种遍历方式
package com.itheima01.map;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class MapLoopDemo01 { //loop循环
public static void main(String[] args) {
Map<Integer,String> map = new HashMap<>();
map.put(1,"张三");
map.put(2,"李四");
map.put(3,"王五");
//1.把key这一列取出来放到set集合中
Set<Integer> keySet = map.keySet();
//2.遍历这个set集合,取出每个key。keySet.for回车
for (Integer key : keySet) {
//3. 根据key获取value
String value = map.get(key);
System.out.println(key + "->" + value);
}
}
}
package com.itheima01.map;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class MapLoopDemo02 {
public static void main(String[] args) {
Map<Integer,String> map = new HashMap<>();
map.put(1,"张三");
map.put(2,"李四");
map.put(3,"王五");
// 1. 把map转化成 Set<Entry> set
Set<Map.Entry<Integer,String>> entrySet = map.entrySet();
// 2. 遍历这样的set, 取出每个entry
for(Map.Entry<Integer,String> entry : entrySet){
//Entry是Map的内部接口,Map有很多Entry,Entry相当于Map属性一样。Map.是接口名直接调用
//如果import java.util.Map.Entry,则Map.Entry可换成Entry
//3. 从这个键值对中,取键,再取值
Integer key = entry.getKey();
String value = entry.getValue();
System.out.println(key + "--" + value);
}
}
}
7.内部接口
package com.itheima02.inner;
import java.lang.reflect.Field;
import java.util.Date;
import com.itheima02.inner.Outer.Inner;
/*
* inner class : 访问受限, 受限于外部类
* 有两个包是不用导入
* 1. java.lang (String,Object)
* 2. 当前类所在的包
* 1和2的子包都要导(如内部接口就在当前包的子包下)
*/
public class InnerDemo {
public static void main(String[] args) {
// new Date()
new String("");
new Object();
// new Field(); //java.lang包的子包
}
}
interface Outer{
//public static final
int I = 1;
//public abstract
void outerMethod();
//public static //外部接口不能创建实例来调用,所以接口名调用,所以静态
interface Inner{ //除了Inner访问受限于Outer,这两个各自独立,new外部类对象不需要new内部类对象
void innerMethod();
}
}
//111111111111111111111111111111111111111111111
class A implements Outer{ //不需要实现Inner
@Override
public void outerMethod() {
}
}
class B implements Outer.Inner{
@Override
public void innerMethod() {
}
}
class C implements Outer,Inner{//上面导过包了,不用写成Outer.Inner
@Override
public void outerMethod() {
}
@Override
public void innerMethod() {
}
}
8.HashMap原理分析
package com.itheima03.impl;
import java.util.*;
/*
* HashMap是最常用的map实现类,因为快
* 1. key不可以重复,但是value可以重复
* 2. key如何判定重复? 先判断hashcode ,再判断equals
* Object: hashcode 和 equals 跟对象真正地址有关
* 重写了hashcode 和 equals,张三山东 覆盖 张三山西
*/
public class HashMapDemo {
public static void main(String[] args) {
// method01();
// method02(); //较method01交换了k和v
new LinkedHashSet<>(); //点进源码,底层是LinkedHashMap
new TreeSet<>(); //TreeMap
new HashSet<>(); //HashMap
//如下有序存取
LinkedHashMap<Person,String> map = new LinkedHashMap<>();
map.put(new Person("张三",18),"山西");
map.put(new Person("吴彦祖",20),"福州");
map.put(new Person("李四",19),"广东");
// map.put(new Person("张三",18),"山东");
Set<Person> keySet = map.keySet();
for (Person key : keySet) {
String value = map.get(key);
System.out.println(key + "---" + value);
}
}
private static void method02() {
//key=Person 自定义类型
HashMap<Person,String> map = new HashMap<>();
map.put(new Person("张三",18),"山西");
map.put(new Person("吴彦祖",20),"福州");
map.put(new Person("李四",19),"广东");
map.put(new Person("张三",18),"山东"); //new出来地址不同
Set<Person> keySet = map.keySet();
for (Person key : keySet) {
String value = map.get(key);
System.out.println(key + "---" + value);
}
HashSet<Object> set = new HashSet<>(); //点进HashSet看源码
//HashSet【collection接口】的底层是HashMap【Map接口】 ,只不过hashset只使用了HashMap key这一列,value这一列不用
}
private static void method01() {
//value=Person 自定义类型
HashMap<String, Person> map = new HashMap<>();
map.put("1号",new Person("张三",18));
map.put("2号",new Person("李四",19));
map.put("3号",new Person("李四",19));
map.put("1号",new Person("王五",20));
//System.out.println(map);
Set<Map.Entry<String,Person>> entrySet = map.entrySet();
for (Map.Entry<String, Person> entry : entrySet) {
String key = entry.getKey();
Person value = entry.getValue();
System.out.println(key + "-" + value);
}
}
}
class Person{
String name;
int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return age == person.age &&
Objects.equals(name, person.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
如下吴彦祖应该在第二个,存取无序,解决:HashMap换成LinkedHashMap
9.统计字符出现个数
package com.itheima03.impl;
import java.util.HashMap;
/*
* 需求: 计算一个字符串中每个字符出现次数。
* 0. 搞一个Map : 记录 字符=次数 (就像画正字选票)
* char int
* 1. 遍历这个字符串,取出每个字符
* 2. 判断Map中是否存在这个字符-> boolean containsKey(Object key) 如果此映射包含指定键的映射关系,则返回 true。
* 3. 有: 在对应的次数+1
* 4. 没有 : 字符=1 存进去
*/
public class CountDemo {
public static void main(String[] args) {
String str = "abcaba";
//泛型不接收基本类型,所以char写成Character,int的包装类Integer
HashMap<Character, Integer> map = new HashMap<>();
for(int i=0; i<str.length();i++){
char c = str.charAt(i); //相应索引访问到相应字符
boolean result = map.containsKey(c);
if(result){ // 存在,次数+1
Integer value = map.get(c); //c是key
// value = value + 1;
// map.put(c,value);
// int count = ++value;
// map.put(c,count);
map.put(c,++value);
}else{ // 不存在, 存入c=1
map.put(c,1);
}
}
System.out.println(map);
}
}
10.断点调试
11.模板
package com.atguigu.test02.abstract_;
/*
* 设计模式?解决问题的套路,代码结构。Java中常用的设计模式有23种。
* 举例:编写一个类,包含一个方法,可以统计 你执行任意代码的运行时间
* 步骤:(1)获取开始时系统时间
* (2)执行xxxx
* (3)获取结束时系统时间
* (4)计算时间差
* 时间的单位:毫秒。提示:System.currentTimeMillis()
*/
public class TestTemplate {
public static void main(String[] args) {
MyCalTime my = new MyCalTime();
long time = my.getTime();
System.out.println("耗时:" + time + "毫秒");
}
}
abstract class CalTime{ //模板类
//可以计算任意一段代码的运行时间 //这里加final的目的是不希望子类重写,改写我的算法的结构
public final long getTime(){
long start = System.currentTimeMillis(); //(1)获取开始时系统时间
doWork(); //(2)执行xxxx
long end = System.currentTimeMillis(); //(3)获取结束时系统时间
return end - start; //(4)计算时间差
}
protected abstract void doWork(); //protected的目的,希望只是子类中进行访问和重写
}
class MyCalTime extends CalTime{
@Override
protected void doWork() { //重写抽象方法
long sum = 0;
for(int i=1; i<=100000; i++){
sum += i;
}
System.out.println("sum = " + sum);
}
}
12.单例
package com.atguigu.test17;
import org.junit.Test;
/*
* 单例:某个类只能有唯一的一个实例对象。如何实现单例?
*
* 1、饿/恶汉式: 不管我们使用者是否需要这个对象,它都上来先给你创建好这个唯一的对象。
* (1)枚举类型
* (2)形式二:class SingleClass
* ①构造器私有化
* ②用一个全局的静态的常量,来保存这个唯一的实例对象
* (3)形式三:class Single
* ①构造器私有化
* ②用一个私有的静态的常量,来保存这个唯一的实例对象
* ③提供一个静态方法,来返回这个常量对象
*
* 2、懒汉式: 延迟创建对象。当使用者来或者这个对象,要用到对象时,我再创建。
* (1)形式一:见下面,考虑线程安全问题和性能问题
* (2)形式二:内部类形式
*
*/
public class Test17 {
@Test
public void test1(){
SingleEnum s1 = SingleEnum.INSTANCE;
SingleEnum s2 = SingleEnum.INSTANCE;
System.out.println(s1 == s2); //true
}
@Test
public void test2(){
// SingleEnum.test();//此时我并没有需要用到这个INSTANCE对象,但是它也创建出来SingleEnum对象,单例恶汉式
}
@Test
public void test3(){
SingleClass s1 = SingleClass.INSTANCE;
SingleClass s2 = SingleClass.INSTANCE;
System.out.println(s1==s2); //true
}
@Test
public void test4(){
Single s1 = Single.getInstance();
Single s2 = Single.getInstance();
System.out.println(s1 == s2);
}
@Test
public void test5(){
LazyClass s1 = LazyClass.getInstance();
LazyClass s2 = LazyClass.getInstance();
System.out.println(s2 == s1);
}
LazyClass s1;
LazyClass s2;
@Test
public void test6(){
//匿名的内部类,继承Thread类。=后面是子类,然后多态
Thread t1 = new Thread(){
public void run(){
s1 = LazyClass.getInstance();
}
};
Thread t2 = new Thread(){
public void run(){
s2 = LazyClass.getInstance();
}
};
t1.start();
t2.start();
try {
//这里用join的目的是,为了两个子线程都执行完,再执行主线程的System.out.println(s1);
t1.join();
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(s1);
System.out.println(s2);
System.out.println(s1 == s2);
}
}
//1111111111111111111111111111111111111111111111111111111111111111
enum SingleEnum{
INSTANCE; //单例,枚举只有一个
// public static void test(){
// //..
// }
}
class SingleClass{ //老版的枚举
public static final SingleClass INSTANCE = new SingleClass();
private SingleClass(){
}
}
class Single{
private static final Single INSTANCE = new Single();
private Single(){
}
public static Single getInstance(){
return INSTANCE;
}
}
//111111111111111111111111111111111111111111111111111111111111111111
class LazyClass{
private static LazyClass instance; //不加final,可以不用new
private LazyClass(){
}
public static LazyClass getInstance(){
if(instance == null){//提高效率,已创建对象就没必要再进去,直接最后return instance;
synchronized(LazyClass.class){//当前类的Class对象,静态方法不能出现this
if(instance == null){//安全判断
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
instance = new LazyClass();
}
}
}
return instance;
}
//安全没问题,但是认为不是最优的,性能差,因为后面没必要再等锁
/* public synchronized static LazyClass getInstance(){
if(instance == null){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
instance = new LazyClass();
}
return instance;
}*/
//有安全问题
/* public static LazyClass getInstance(){
// return new LazyClass();//错误的,每次都new新的对象
if(instance == null){ //下次有的时候就不进来了
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
instance = new LazyClass();
}
return instance;
}*/
}
//11111111111111111111111111111111111111111111111111111
class Lazy{
private Lazy(){
}
private static class Inner{
public static final Lazy INSTANCE = new Lazy();//在内部类中,创建外部类的唯一对象
}
public static Lazy getInstance(){
return Inner.INSTANCE; //用到getInstance方法才会new Lazy(),也是懒汉式
}
}
13.工厂
package com.atguigu.test12;
import org.junit.Test;
/*
* 一、工厂设计模式:为了解耦合,把对象的创建者与对象的使用者分开。
* Java:批量生产对象
* Java:没有工厂,需要对象,自己new
* 分工:把生产(创建)对象与使用对象分开了,解耦合
*
* 1、简单工厂模式:
* class SimpleFactory2{
public static Car getCar(String type){
if("宝马".equals(type)){
return new BMW();
}else if("奔驰".equals(type)){
return new Benz();
}
return null;
}
}
* 优点:代码比较简洁
* 缺点:如果增加新的产品类型,需要修改工厂类。违反了面向对象的一个开发原则:对扩展开放,对修改关闭
*
* 2、工厂方法模式:特点:一个产品就对应一个工厂类
interface Che{
void run();
}
class BaoMa implements Che{
@Override
public void run() {
System.out.println("宝马");
}
}
interface GongChang{
Che getChe();
}
class BaoMaFactory implements GongChang{
@Override
public Che getChe() {
return new BaoMa();
}
}
*/
public class TestFactory {
@Test
public void test03(){
Car c = SimpleFactory2.getCar("奔驰");
c.run();
}
@Test
public void test02(){
Car c = SimpleFactory.getCar(); //静态
c.run();//这里也是运行宝马的run(),但是从头至尾没有出现BMW类,解耦合
}
@Test
public void test01(){
//没有工厂,如下创建对象和使用对象是同一个人完成
BMW b = new BMW(); //比如spring容器,new时要初始化很多配置信息才创建一个对象
//使用对象,调用方法
b.run();
}
}
interface Car{
void run();
}
class BMW implements Car{
@Override
public void run() {
System.out.println("宝马让你在车里面哭");
}
}
class Benz implements Car{
@Override
public void run() {
System.out.println("奔驰让你在车盖上哭");
}
}
class Audi implements Car{
@Override
public void run() {
System.out.println("奥迪让你在...");
}
}
//111111111111111111111111111111111111111111111
class SimpleFactory{ //工厂类
public static Car getCar(){
return new BMW();
}
}
class SimpleFactory2{
public static Car getCar(String type){
if("宝马".equals(type)){
return new BMW();
}else if("奔驰".equals(type)){
return new Benz();
}
return null;
}
}
package com.atguigu.test12;
/*
* 2、工厂方法模式
* 出发点:(1)为了生产对象与使用对象分开 (2)如果增加新产品,就不需要修改原来的工厂类
* 优点:遵循了增加新产品,不修改原来的类的原则。 缺点:类太多了,一种车一个工厂
*/
public class TestFactory2 {
public static void main(String[] args) {
BaoMaFactory bf = new BaoMaFactory();
Che c = bf.getChe();
c.run();
}
}
interface Che{
void run();
}
class BaoMa implements Che{
@Override
public void run() {
System.out.println("宝马");
}
}
class BenChi implements Che{
@Override
public void run() {
System.out.println("奔驰");
}
}
class AoDi implements Che{
@Override
public void run() {
System.out.println("奥迪");
}
}
//111111111111111111111111111111111111111111111
interface GongChang{
Che getChe();
}
class BaoMaFactory implements GongChang{
@Override
public Che getChe() {
return new BaoMa();
}
}
class BenChiFactory implements GongChang{
@Override
public Che getChe() {
return new BenChi();
}
} //只需要增加一个工厂类,专门生产奥迪车,不动上面代码
package com.atguigu.test12;
public class TestFactory3 {
public static void main(String[] args)throws Exception {
Vehicle c = SimpleFactory3.getVehicle("com.atguigu.test12.QQ");
c.run();
Vehicle c2 = SimpleFactory3.getVehicle("com.atguigu.test12.Aoto");
c2.run();
}
}
interface Vehicle{
void run();
}
class QQ implements Vehicle{
@Override
public void run() {
System.out.println("qq车");
}
}
class Aoto implements Vehicle{
@Override
public void run() {
System.out.println("奥拓");
}
}
//111111111111111111111111111111111111111
class SimpleFactory3{
public static Vehicle getVehicle(String className)throws Exception{
Class clazz = Class.forName(className);
return (Vehicle) clazz.newInstance(); //clazz.newInstance()返回Object强转为Vehicle类
}
}
14.代理
package com.atguigu.test13;
import org.junit.Test;
/*
* 当前这个类做一些事情,不太方便,因为这个事情是多变,重复的,我可以交给代理
* 例如:项目经理说,在测试环境即开发阶段(不是生产环境,上线就是生产环境),测试一下每一个方法的运行时间,并且记录方法运行的日志。开发完了,项目经理说,把那些代码(就是"add方法开始执行"等)都去掉。
*
*代理模式:(1)主题接口:要求【代理类DAOProxy】与【被代理类UserDAOImpl】实现同一个接口,例如:DAO接口。(2)被代理者。(3)代理者:必须持有被代理者的引用。
*
*上面是静态代理模式 缺点:一个代理类只能替一个代理主题(接口)代理工作,多定义一个接口又要写一个代理类。所以用动态代理模式。
*/
public class TestAgent {
public static void main(String[] args) {
GoodsDAOImpl dao = new GoodsDAOImpl(); //正式代码不是下面测试代码
dao.add(); //添加商品 //没有其他的
}
@Test
public void test02(){
//new GoodsDAOImpl()被代理者对象,new DAOProxy(x)代理者对象
DAO d = new DAOProxy(new GoodsDAOImpl());
d.add();
}
@Test
public void test01(){
DAO d = new DAOProxy(new UserDAOImpl());
d.add();
}
}
interface DAO{
void add();
/* void update();
void delete();
void select();*/
}
class UserDAOImpl implements DAO{ //被代理类
@Override
public void add() {
// System.out.println("add方法开始执行"); //这些代码冗余
// long start = System.currentTimeMillis();
System.out.println("添加用户"); //这行的上下代码就是方法的日志
// long end = System.currentTimeMillis();
// System.out.println("运行时间:" + (end-start));
// System.out.println("add方法执行结束");
}
}
class GoodsDAOImpl implements DAO{ //被代理类
@Override
public void add() {
// System.out.println("add方法开始执行");
// long start = System.currentTimeMillis();
System.out.println("添加商品");
// long end = System.currentTimeMillis();
// System.out.println("运行时间:" + (end-start));
// System.out.println("add方法执行结束");
}
}
//111111111111111111111111111111111111111111111111111111111111111111111111111
class DAOProxy implements DAO{ //代理类
private DAO dao;//持有被代理者的引用,因为核心业务逻辑仍然交给被代理者自己完成
public DAOProxy(DAO dao) { //传入对象
super();
this.dao = dao;
}
public void add(){
System.out.println("add方法开始执行");
long start = System.currentTimeMillis();
// System.out.println("添加商品");//核心业务逻辑交给被代理者自己完成
dao.add(); //调用
long end = System.currentTimeMillis();
System.out.println("运行时间:" + (end-start));
System.out.println("add方法执行结束");
}
}
package com.atguigu.test13;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import org.junit.Test;
/*
* 动态代理模式:Spring框架中。优点:一个代理工作处理器,可以替多个代理主题(接口)代理工作,只有代理工作内容一样就可以(比如都要代理做记录时间)。
* 需要:(1)编写一个代理工作处理器的类,这个类必须实现一个接口InvocationHandler
* (2)用JDK中提供了一个Proxy类,来创建代理类的对象 (3)调用方法
* new ProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
* 如上方法参数一:被代理者的类加载器对象
* 参数二:被代理者实现的接口们
* 参数三:代理者替被代理者要完成的工作的处理器对象
*/
public class TestProxy {
@Test
public void test01() {
AImpl a = new AImpl();//被代理者
ClassLoader loader = a.getClass().getClassLoader();
Class<?>[] interfaces = a.getClass().getInterfaces();
Handler h = new Handler(a);
A proxy = (A) Proxy.newProxyInstance(loader, interfaces, h);
proxy.a(); // a方法开始执行,a方法被执行,运行时间:1,a方法执行结束
}
@Test
public void test02() {
BImpl b = new BImpl();//被代理者
ClassLoader loader = b.getClass().getClassLoader();
Class<?>[] interfaces = b.getClass().getInterfaces();
Handler h = new Handler(b);
B proxy = (B) Proxy.newProxyInstance(loader, interfaces, h);
proxy.b();
}
}
//111111111111111111111111111111111111111111111111111111111111111111111111111111
class Handler implements InvocationHandler{
private Object target;//被代理者对象
public Handler(Object target) { //构造器就是让外面传进来,上面定义的target=外面传的target
super();
this.target = target;
}
/*
* 如下方法不是程序调用的,是一会执行代理类对象的方法时自动调用:
* 参数一:代理类的对象
* 参数二:被代理者要执行的方法
* 参数三:被代理者要执行的方法需要的实参列表
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println(method.getName() + "方法开始执行");
long start = System.currentTimeMillis();
// method.invoke(obj, args);//obj是要求写被代理者对象
Object value = method.invoke(target, args); //被代理方法有返回值
long end = System.currentTimeMillis();
System.out.println("运行时间:" + (end-start));
System.out.println(method.getName() + "方法执行结束");
return value; //必须要返回
}
}
//11111111111111111111111111111111111111111111111111111111111111111111111111
interface A{ //主题1
void a();
}
class AImpl implements A{ //被代理者1
@Override
public void a() {
System.out.println("a方法被执行");
}
}
interface B{ //主题2
void b();
}
class BImpl implements B{ //被代理者2
@Override
public void b() {
System.out.println("b方法被执行");
}
}
内容总结
以上是互联网集市为您收集整理的【Java】基础_16_hashcode/哈希表原理,Map/内部接口,断点调试,设计模式全部内容,希望文章能够帮你解决【Java】基础_16_hashcode/哈希表原理,Map/内部接口,断点调试,设计模式所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。