范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

设计模式JDKampampampSpringampampampGuava各有千秋

  何为监听者模式 ?
  第一就是为啥我强调事件二字 ,因为他是目标 . 在我们开发中绝对见到过一堆后缀是  Listener  的类, 这个就是监听者模式, 监听者模式是一种CS开发架构  ,很好的做了一种设计的解耦,监听者注册到一个邮局中,订阅某种事件(提前说好了), 邮局会按需求发布消息, 监听者会及时收到消息来处理 . 其中整个Java开发环境中 , JDK已经帮我们定义好了接口 , Spring就是基于JDK接口下实现的, Guava则是另一种实现方式, 各有千秋 , 大家看看吧 , 到底是回调好还是阻塞, 还是Guava这种方式呢,
  他和观察者模式有何区别呢 ? 我们有机会再讲  1. Java原生规范1. EventObject
  事件对象 , 他需要一个事件源 , 用构造函数传递的  public class EventObject implements java.io.Serializable {     protected transient Object  source;      public EventObject(Object source) {         if (source == null)             throw new IllegalArgumentException("null source");          this.source = source;     }     ........... 其他省略  }2. EventListener
  事件监听者,他是负责监听事件的 , JAVA提供的是一个空接口, 让我们根绝需求写  public interface EventListener { }3. 总结
  我们发现 java 提供的只提供了一个事件对象 ,和一个事件监听器 ,所以需要我们遵守这个规范去开发 2. Java规范设计一个监听者模式 - 基于回调模式1. 事件源 - EventSource
  一般情况下 都会设置成一个 Object 类型的 , 不需要我们去设计一个,为了体现设计模式的角色,我们就设计了一个 @ToString @Setter @Getter public class EventSource {     private String name;     private String info; }2. 事件对象 - EventObject
  这里我们继承了 EventObject , 只是简单地实现了一下 , 并没有做过多的包装 public class CoreEventObject extends EventObject {     public CoreEventObject(EventSource source) {         super(source);     } }3. 事件监听者 - EventListener
  这里我们真正的监听者 , 一般情况下都需要设计成一个 函数式接口 , 我这个是和Spring框架学习的 , 因为函数式接口才能体现回调 , @FunctionalInterface public interface CoreEventListener extends EventListener {      void onEventObject(E event); }4. 事件发布者 - EventPublisher
  事件发布者 ,因为没有发布的事件对象, 哪来的监听 public class EventPublisher {      private CoreEventListener listener;       public EventPublisher(CoreEventListener listener) {         this.listener = listener;     }       public void publish(E object){         System.out.println("发布事件 : " + object);         // 传给 CoreEventListener         listener.onEventObject(object);     } }5. 测试Demopublic class TestDemo {     public static void main(String[] args) {         // 1. 创建一个事件发布者         EventPublisher publisher = new EventPublisher<>(new CoreEventListener() {             @Override             public void onEventObject(CoreEventObject event) {                 System.out.println("接收到事件源 : " + event.getSource() + " , 当前线程 : " + Thread.currentThread().getName());              }         });          // 2. 发布一个事件对象          publisher.publish(getCoreEventObject());     }      private static CoreEventObject getCoreEventObject(){         ..... 此处省略          return eventObject;     } }
  输出结果 : 发布事件 : com.example.listener_design_pattern.CoreEventObject[source=EventSource(name=事件源, info=Sat Nov 09 14:34:50 CST 2019)] 接收到事件源 : EventSource(name=事件源, info=Sat Nov 09 14:34:50 CST 2019) , 当前线程 : main
  我们发现我们成功地接收到了事件对象 和 事件源 , 这个就是钩子函数的魅力 . 其实你只是做了一个事件发布你无心观察其他的东西 , 只需要一个监听者就可以做到监听了 , 这样你的事件发布 和 监听 完全就解耦了 .其实底层就是一个地址引用 . 3. 回调函数存在的问题 ?1. 我们的问题 ?
  很多场景下,我们的发布事件和监听事件完全在两个线程中,那么我们如何拿到事件对象呢 ?
  如果我们简单使用一下 , 会这么写 ? public class TestEventListener implements CoreEventListener {      private CoreEventObject object;      @Override     public void onEventObject(CoreEventObject object) {          // 赋值给成员变量          this.object = object;     }      // 获取成员变量      public CoreEventObject getObject() {         return object;     } }
  测试一下 : public class TestDemo {      public static void main(String[] args) {          TestEventListener listener = new TestEventListener();         CoreEventObject object = listener.getObject();         // 先去拿 ,后去发布         System.out.println(object.getSource());          EventPublisher publisher = new EventPublisher<>(listener);         publisher.publish(getCoreEventObject());     }       private static CoreEventObject getCoreEventObject(){             ....          return eventObject;     }  }
  输出结果 Exception in thread "main" java.lang.NullPointerException     at com.example.listener_design_pattern.TestDemo.main(TestDemo.java:28)
  有些人就会说 , 你这不对哇 ,你当然拿不到了 ,因为人家还没发布了 ,但是在多线程 ,在解耦的情况下 ,你哪知道对面何时发布结束了 , 你再去拿呢 ? 那就需要java的多线程知识了 ,Future 给我们带来了提醒 , 就是阻塞的思想 , 只有监听者真正地收到对象 , 我们才能去拿 . 2. 解决问题
  了解过我前面提到的那一节 FutureTask  是如何实现的 ,我觉得问题就迎刃而解了 .public class TestEventListener implements CoreEventListener {     private CoreEventObject object;      /**      * 当 X = 0 ,代表 obj还没有初始化了      * 当 x = 1 , 代表 obj 以及初始化了 , 已经接收到了      */     private static volatile int x = 0;      @Override     public void onEventObject(CoreEventObject object) {         this.object = object;         // 收到改成 1         x = 1;     }      public CoreEventObject getObject() {         while (true) {             if (x == 1) {                 break;             }         }         // 拿到对象,再设置为1         x = 0;         return object;     } }
  由于这个解决方案,会使得执行 getObject()   的线程一直的阻塞下去,就是死循环下去,我们必须一个线程去执行这个方法 ,public class TestDemo {     public static void main(String[] args) {         TestEventListener listener = new TestEventListener();         // 新建一个线程去接收         Thread thread = new Thread(() -> {             System.out.println("我开始接收对象 : " + System.currentTimeMillis());             CoreEventObject object = listener.getObject();             System.out.println("成功接收对象 : "+object.getSource());         });         thread.start();         // 新建一个线程去发布         EventPublisher publisher = new EventPublisher<>(listener);         new Thread(()->{             publisher.publish(getCoreEventObject());         }).start();     }      private static CoreEventObject getCoreEventObject(){         try {             Thread.sleep(1000);         } catch (InterruptedException e) {             e.printStackTrace();         }         EventSource source = new EventSource();         source.setName("事件源");         source.setInfo("" + System.currentTimeMillis());         return new CoreEventObject(source);     } }
  输出结果 : 我开始接收对象 : 1573282924555 发布事件 : com.example.listener_design_pattern.CoreEventObject[source=EventSource(name=事件源, info=1573282925590)] 成功接收对象 : EventSource(name=事件源, info=1573282925590)
  我们我们接收的时候是在1573282924555的时间搓 , 而真正拿到的对象确实在1573282925590发布的 , 这个就完全在俩时间轴上,所以我们成功的解决了问题 . 4. Spring 中的 ApplicationListener1. ApplicationEventClass to be extended by all application events. Abstract as it doesn"t make sense for generic events to be published directly.
  此类被所有的  application events   所继承 。抽象的原因是因为直接发布这个ApplicationEvent  是没有意义的。2. ApplicationListenerInterface to be implemented by application event listeners. Based on the standard java.util.EventListener interface for the Observer design pattern.
  这个接口被所有的  application eventlisteners.  所实现 , 基于Java的java.util.EventListener  接口规范3. 开始使用
  我们有一个需求就是 ,我们有一个服务会从远程不断的去拉去配置信息 ,一旦有改变就会发布配置信息 . 1. Config - 事件源@ToString @Setter @Getter public class Config {     private String namespace;     private Map info; }2. ConfigEvent - 事件对象// 这个注解,我们是根据Spring源码看到的 , 所以一致性,我就加了 @SuppressWarnings("serial") public class ConfigEvent extends ApplicationEvent {      public ConfigEvent(Config source) {         super(source);     } }3. ConfigEventListener - 事件监听者@Component public class ConfigEventListener implements ApplicationListener , Ordered, InitializingBean {      @Override     public void onApplicationEvent(ConfigEvent event) {         System.out.println("接收到更新信息 : " + event.getSource()+" , 当前线程 : "+Thread.currentThread().getName());     }     // 保证执行顺序 , 多个 ConfigEventListener就需要实现这个接口     @Override     public int getOrder() {         return Ordered.HIGHEST_PRECEDENCE;     }      // 初始化以后要做什么 ?      @Override     public void afterPropertiesSet() throws Exception {         System.out.println("初始化当前ConfigEventListener");     } }5 . ConfigServer - 配置中心服务@Service public class ConfigServer {      // 注入applicationContext,因为只有他才可以执行发布事件     @Autowired     private ApplicationContext applicationContext;      // 这个是开启异步 ,后面会说到     // @Async     public void publishConfig(){         // 需要发布 --- > 改变的事件          System.out.println("发布事件成功 , 当前线程 : "+Thread.currentThread().getName());         applicationContext.publishEvent(getChange());     }       public ConfigEvent getChange(){         Config config = new Config();         config.setNamespace("application");         HashMap conf = new HashMap<>();         conf.put("server.port", 8088);         config.setInfo(conf);         return  new ConfigEvent(config);     } }6. 启动测试@SpringBootApplication public class SpringListenerApplication implements CommandLineRunner {      public static void main(String[] args) {         SpringApplication.run(SpringListenerApplication.class, args);     }      @Autowired     private ConfigServer server;      @Override     public void run(String... args) throws Exception {         server.publishConfig();     } }
  输出结果 : ..... 初始化当前ConfigEventListener ....  发布事件成功 , 当前线程 : main 接收到更新信息 : Config(namespace=application, info={server.port=8088}) , 当前线程 : main
  所以一个 Spring-Boot  的事件监听还是很简单的 ,类比到Spring  一个道理,相信懂得人都知道 . 但是又一个问题是我们的 发布和监听都是 main线程 ,不好吧 ,玩意有很多事件了 ?4. 开启异步发布
  需要两个注解 @EnableAsync  启动Async功能 , 和@Async  某个方法使用异步执行发布事件成功 , 当前线程 : SimpleAsyncTaskExecutor-1 接收到更新信息 : Config(namespace=application, info={server.port=8088}) , 当前线程 : SimpleAsyncTaskExecutor-1
  我们发现就出现了线程池执行 , 这个理的线程池 ,是可以进行配置的 , 只需要我们显式的注入下面这个 SimpleAsyncTaskExecutor   Bean 就可以了@Bean public SimpleAsyncTaskExecutor simpleAsyncTaskExecutor() {     SimpleAsyncTaskExecutor executor = new SimpleAsyncTaskExecutor();     // 需要传入一个 ThreadFactory实现类 , 所以看过我前面写的文章应该会写这个,比如 JUC- Executor那节     executor.setThreadFactory(new MyThreadFactory("anthony"));     return executor; }
  输出结果 : 发布事件成功 , 当前线程 : anthony-1 接收到更新信息 : Config(namespace=application, info={server.port=8088}) , 当前线程 : anthony-15 . 多个监听器顺序执行
  你可以跟我一样选择实现 ApplicationListener  和Ordered   ,或者你可以直接实现SmartApplicationListener  都一样的哈,没有哪个好哪个不好
  监听器 一 : @Component public class ConfigEventListenerStart implements ApplicationListener , Ordered, InitializingBean {      @Override     public void onApplicationEvent(ConfigEvent event) {         System.out.println("ConfigEventListenerStart 接收到更新信息 : " + event.getSource()+" , 当前线程 : "+Thread.currentThread().getName());     }      @Override     public int getOrder() {         return Ordered.HIGHEST_PRECEDENCE;     }       @Override     public void afterPropertiesSet() throws Exception {         System.out.println("初始化当前监听器 : " + this.toString());     } }
  监听器 二 : @Component public class ConfigEventListenerEnd implements ApplicationListener , Ordered, InitializingBean {      @Override     public void onApplicationEvent(ConfigEvent event) {         System.out.println("ConfigEventListenerEnd  接收到更新信息 : " + event.getSource()+" , 当前线程 : "+Thread.currentThread().getName());     }      @Override     public int getOrder() {         return Ordered.HIGHEST_PRECEDENCE-1;     }      @Override     public void afterPropertiesSet() throws Exception {         System.out.println("初始化当前监听器 : " + this.toString());     } }
  输出结果 : 初始化当前监听器 : com.example.springlistener.listener.ConfigEventListenerEnd@6b54655f 初始化当前监听器 : com.example.springlistener.listener.ConfigEventListenerStart@665e9289 .....  发布事件成功 , 当前线程 : anthony-1 ConfigEventListenerStart 接收到更新信息 : Config(namespace=application, info={server.port=8088}) , 当前线程 : anthony-1 ConfigEventListenerEnd  接收到更新信息 : Config(namespace=application, info={server.port=8088}) , 当前线程 : anthony-1    5. Guava 中的 EventBus
  Guava的EventBus 就是一个很好的事件注册发布的管理工具 , 他属于一种推送的模式 , 跟spring的很相似,  1. 依赖     com.google.guava     guava     28.0-jre 2. 快速开始
  主要的对象就是 ,  EventBus   事件总线, 他是管理所有监听者(或者叫做订阅者) ,通过EventBus#register   或者EventBus#unRegister   来管理的 , 同时监听者要有监听的事件 , 这里是基于方法级别的 (注意方法只能有一个参数,就是监听的事件), 需要在方法上加上@Subscribe   注解来表示监听 ,EventBus  可以通过EventBus#post  方法来发布事件 , 对应类型的监听者就会收到 . 同时EventBus  可以处理异常public class QuicklyStart {      public static void main(String[] args) {         // 创建一个 事件总线         EventBus bus = new EventBus(new SubscriberExceptionHandler() {             @Override             public void handleException(Throwable exception, SubscriberExceptionContext context) {                 // 处理订阅者异常信息                 System.out.println("异常信息 : "+exception.getMessage() + ", 异常事件 : " + context.getEvent());             }         });          // 注册你的监听器 , 其实更加准确来说是订阅者 , 他属于一种发布订阅模式         bus.register(new EventListener());          // 事件总线发布事件         bus.post("sb");          // 事件总线发布事件         bus.post(new Event("hello Guava"));      }   }  /**  * 事件源  */ class Event {      String msg;      public Event(String msg) {         this.msg = msg;     }      @Override     public String toString() {         return "Event{" + "msg="" + msg + """ + "}";     } }  /**  * 监听器  */ class EventListener {      /**      * {@link Subscribe} 一个这个代表一个订阅者,EventBus会将符合的事件发布到对应的订阅者上 , 但是不支持java的基本数据类型, int 之类的      *      * @param event      */     @Subscribe     public void onEvent(Event event) {         System.out.println("当前线程 : " + Thread.currentThread().getName() + ", 接收到事件 : " + event);     }       @Subscribe     public void onStringEvent(String event) {         error(); // 模拟异常         System.out.println("当前线程 : " + Thread.currentThread().getName() + ", 接收到事件 : " + event);     }      private void error() {         int i = 1 / 0;     } }
  输出 : 异常信息 : / by zero, 异常事件 : sb 当前线程 : main, 接收到事件 : Event{msg="hello Guava"}3. 基本原理
  其实很简单 , 第一注册的时候 : /** Registers all subscriber methods on the given listener object. */ void register(Object listener) {   // 其实就是注解扫描 , 然后把元信息都给整出来 Multimap, Subscriber> listenerMethods = findAllSubscribers(listener);  for (Entry, Collection> entry : listenerMethods.asMap().entrySet()) {   Class<?> eventType = entry.getKey();   Collection eventMethodsInListener = entry.getValue();     // 查找有没有    CopyOnWriteArraySet eventSubscribers = subscribers.get(eventType);      // 没有创建一个对象   if (eventSubscribers == null) {     CopyOnWriteArraySet newSet = new CopyOnWriteArraySet<>();     eventSubscribers =         MoreObjects.firstNonNull(subscribers.putIfAbsent(eventType, newSet), newSet);   }      // 添加进去 ,其实是 Subscriber对象 , 把method信息, 对象信息全部封装进去了   eventSubscribers.addAll(eventMethodsInListener); } }
  第二就是 发布   public void post(Object event) {       // 根据事件获取对应的 Subscriber     Iterator eventSubscribers = subscribers.getSubscribers(event);     if (eventSubscribers.hasNext()) {         // 发布出去       dispatcher.dispatch(event, eventSubscribers);     } else if (!(event instanceof DeadEvent)) {       // the event had no subscribers and was not itself a DeadEvent       post(new DeadEvent(this, event));     }   }    @Override void dispatch(Object event, Iterator subscribers) {   checkNotNull(event);   checkNotNull(subscribers);     // 获取当前线程的队列 ,用ThreadLocal维护的线程安全, 其实是为了安全   Queue queueForThread = queue.get();     // 创建一个事件对象   queueForThread.offer(new Event(event, subscribers));    if (!dispatching.get()) {     dispatching.set(true);     try {       Event nextEvent;       while ((nextEvent = queueForThread.poll()) != null) {         while (nextEvent.subscribers.hasNext()) {             // 处理           nextEvent.subscribers.next().dispatchEvent(nextEvent.event);         }       }     } finally {       dispatching.remove();       queue.remove();     }   } }    /** Dispatches {@code event} to this subscriber using the proper executor. */   final void dispatchEvent(final Object event) {     executor.execute(         new Runnable() {           @Override           public void run() {             try {                 // 关键点 ,就是这                invokeSubscriberMethod(event);             } catch (InvocationTargetException e) {                 // 出现异常直接就 ... 调用异常回调方法了               bus.handleSubscriberException(e.getCause(), context(event));             }           }         });   }      @VisibleForTesting   void invokeSubscriberMethod(Object event) throws InvocationTargetException {     try {         // 原来如此 , .........method.invok 真.... 所以可以抓取异常       method.invoke(target, checkNotNull(event));     } catch (IllegalArgumentException e) {       throw new Error("Method rejected target/argument: " + event, e);     } catch (IllegalAccessException e) {       throw new Error("Method became inaccessible: " + event, e);     } catch (InvocationTargetException e) {       if (e.getCause() instanceof Error) {         throw (Error) e.getCause();       }       throw e;     }   }
  所以这个玩意很简单 , 原理一看就分析出来了 6. 总结
  我们发现我们的自己实现的监听者和 Spring  和Guava   这俩种实现有啥区别 , 无非就是我们自己实现的监听者模式, 对于 listener 的管理,没有做 , 我们只是一个 Publisher 一个 Listener,一对一的关系 , 这样子就很不好, 100个监听者就需要100个发布者 , 不符合设计模式的原则 , 所以参考Guava  ,我们发现他无非做的就是一个对于Listener 的管理 , 但是有一个细节希望大家知道, 对于监听者模式 , 万一事件发布失败了 , 我们如何知道, 所以Guava   至少帮我们做了 , 他不是基于回调机制的, 而是使用了Java  的Method#invoke   ,看需求而定吧 , 只不过回调更加轻量级,

LG友达光电正在研发480HZ液晶面板根据外媒TFTCentral消息,目前LGDisplay以及友达光电(AUO)正在开发480Hz刷新率液晶面板技术。这种超快刷新率面板有望在2022年年底前进行量产,预计将在202小米12或在双12当天发布要抢骁龙8Gen1首发关于小米发布会的消息,早有爆料称12月16日会举办,但是最新的消息指出,小米年度新品发布会将会在12月12日举办,也就是双12当天。如果想要抢到骁龙8Gen1处理器的首发,那么小米手机全部国产硬件软件,落后好几代,会有人买吗?这都什么时候了,我直白点说,哪怕是现在国产手机回到3年前的水平,我相信依然有一大把人要支持国产手机。为什么这么说呢?大家往下看!国产手机倒退还有人买吗?我们现在用的无论是系统还是硬为什么冬天很少有人用空调制热?这4点原因是关键随着科技的发展,空调几乎是入住到了每家每户。但是大部分人应该也注意到了,人们在夏天使用空调的频率很高,可到了冬天,空调基本就闲置了。这不禁让我们感到好奇,为什么空调有制热的功能,可专业运动手表成蓝海市场,如骏入局天时地利与人和近年来,国人空前高涨的运动健身热情催生出了一片蓝海市场。根据阿里体育统计,在刚刚结束的双十一购物狂欢中,天猫淘宝双平台的体育消费总额突破60亿元,同比增长17。6,成交人数突破20星巴克中国内地首家共享空间概念店上海开业加拿大鹅将在哈尔滨南京宁波等地新设门店美通社头条要闻摘要星巴克中国内地首家共享空间概念店诞生。加拿大鹅任命PaulCadman为亚太区总裁。龙腾出行和羽田机场达成战略合作。DHL快递试运行德邮敦豪集团首辆氢燃料卡车。亚马逊云科技国产软件难爆发,压力来到了大厂这边撰文牛耕编辑赵艳秋中国SaaS市场水温变暖中国SaaS市场的水温正逐渐变暖,从事客户关系管理软件的销售易感觉到了这种变化。之前都是我们追着客户打单,现在好多客户带着明确需求来找我们或许成就华为的是联想1984年,计研所出资出人成立联想,柳传志为总经理,倪光南院士为总工程师。1984年到1994年的这十年发生了什么呢?这期间发生的一些事,或许间接的促成了微软苹果华为的崛起!是不是怡口纯E系列净水器让泡茶烹饪风味倍增专注于水处理领域96年的怡口净水,连续多年位于全屋净水行业的前列,而在疫情的特殊时期,怡口仍在行业内保持着领跑的地位,持续投入产品研发。作为传承近百年技术积淀的高端品牌,怡口的核心79元再战两年!华为5折换屏服务上线涵盖22款机型近日,华为为有换屏需求的用户推出了华为手机五折换屏服务,根据华为官方海报显示,换屏价格从79元至879元不等,涵盖华为nova7SE华为Mate40华为P50华为MateX2等22实现0突破!中企埋头研发15年,造出国产首款高性能显卡GPU文BU审核张子扬校正知秋GPU也就是图形处理器,一个在个人电脑汽车服务器人工智能等领域做着图像和图形相关运算工作的微处理器,其重要性显而易见。随着人工智能的逐渐发展壮大,GPU将有
阿里云出事了事情源于阿里云发现了一个很严重的计算机漏洞!那是什么级别的计算机漏洞呢?计算机漏洞简单来说就是软件上的一个缺陷,可以使得别人可以攻击或者远程操控您的计算机。但这里有个区别,如果这个阿里云这次冤不冤?文章来自微信公众号记忆承载。欢迎关注阅读全文。有读者转了一篇某大V批阿里的文章给我看,内容是阿里云被工信部暂停合作单位的处罚。这个作者的意见是这样的,大概是说,阿里发现了服务器中的(世界首富)马斯克追忆破产边缘每天醒来,在梦中哭了一夜要么死得安然,要么活得灿烂。马斯克每天早晨醒来,都发现枕头是湿漉漉的,在梦中哭了一夜,一边嚼着玻璃,一边凝视深渊。马斯克追忆破产边缘的日子尘心帆语乔布斯被苹果开除过亚马逊总裁贝佐斯从ORIN平台看智能驾驶计算平台方向,受益标的一览一英伟达ORIN平台已经签约十余款旗舰车型蔚来汽车在2021NIODAY上发布旗下第五款车型ET5,定位中型智能电动轿跑,应用英伟达ORIN平台,是蔚来ET7后第二款应用英伟达OR雪梨淘宝店铺抖音小红书账号被封蓝鲨消费早报12月13日雪梨淘宝店铺抖音小红书账号被封蓝鲨消费早报12月13日短视频直播带货新消费快讯1雪梨淘宝店铺抖音小红书账号被封2机能性食品品牌山海植物完成数百万元种子轮融资3零食连锁企业零食女孩获蓝思科技光伏玻璃签约,超薄玻璃加工优势促全流程布局落地12月15日,2021中国光伏行业年度大会暨(滁州)光伏创新发展高峰论坛在安徽滁州召开。会上,工信部国家能源局相关人士均表示,将推动我国光伏产业持续健康高质量发展。同时,蓝思科技在手机号隐藏着太多个人信息,不要轻易告诉陌生人,免得受损互联网的广泛使用,的确方便了我们日常生活,饿了可以足不出户吃到香味俱全美食,穿戴方面也可以通过互联网购买到心怡漂亮的衣服,一机在手知天下事。生活质量是提高了,我们是不是还忽略了另一为什么互联网大厂BAT不去涉足智能制造?本人是服装制造业从业者,虽然一直以来干的都是苦活累活,也没有赚到几个钱,但是还是有一点体悟的。那就是干生产的是产业链最下游的存在,是利润率最低的一层,就是赚点辛苦钱。比生产更高一级博主透露三星GalaxyS22Ultra将拥有迄今智能手机中表现最好的摄像头2022年1月,三星预计将宣布新的GalaxyS22系列智能手机。GalaxyS22Ultra将是S22系列的旗舰设备,它将在相机部分有多项改进。当比较目前的旗舰智能手机时,评测机中国A股能与宁德媲美的这5家新能源科技企业,未来可期A股市场上,能够代表未来十年的新能源硬核科技,并且还能与宁德时代过去十年谷价涨幅媲美的高端制造骨干,这5将新能源科技企业绝对可以当选。虽然呢,全网上号称是高端制造的公司数不胜数,但值得骄傲!盘点2021年科技的5大突破,每样都在让中国人抬起头新的一年就快来了,很快要和2021年告别了,在年终岁尾的时候,盘点中国2021年科技的五大突破,真是激动人心!第一大科技突破,中国能实现存储光长达一小时的时间。高科技时代,人们常用