首页 > 编程语言 >2-1-4.spring源码--AbstractApplicationContext

2-1-4.spring源码--AbstractApplicationContext

时间:2023-02-20 16:01:13浏览次数:38  
标签:NAME beanFactory -- spring BEAN refresh bean 源码 context


Spring源码–AbstractApplicationContext

概述

江湖上流传这样一个传说,只要把spring的refresh()搞明白,spring就学的七七八八了。今天来盘一下refresh方法,这个这是一个困难点了。

学习refresh()先要知道这个方法承接的类,对于AbstractApplicationContext类,前面也介绍了,他的实现类ClassPathXmlApplicationContext类,执行下方代码:

ApplicationContext applicationContext= new ClassPathXmlApplicationContext("x.xml");
B b=applicationContext.getBean(B.class);

在创建对象使用构造方法时候调用了refresh方法,也就是说,在程序启动,构建bean的过程中执行refresh方法 。下面我们看下具体的refresh方法包括那些内容。

源码

@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 准备更新上下文,设置开始时间,标记活动标志,初始化配置文件中的占位符
prepareRefresh();

// 一、 web工程 AbstractRefreshableApplicationContext
// 将 bean 定义加载到给定的 BeanFactory 中
// 二、 SpringBoot GenericApplicationContext,实际 register 过程在 invokeBeanFactoryPostProcessors 中
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

// 准备 BeanFactory 以便在此上下文中使用。
prepareBeanFactory(beanFactory);

try {
// Allows post-processing of the bean factory in context subclasses.
// 在 AbstractApplicationContext#postProcessBeanFactory 为空实现,留给子类做扩展,不同 ApplicationContext 实现不同,不作详细描述
postProcessBeanFactory(beanFactory);

// Invoke factory processors registered as beans in the context.
// Spring 的 SPI
// 先调用 BeanDefinitionRegistryPostProcessor 和 ImportBeanDefinitionRegistrar 的实现类
// 再调用 BeanFactoryPostProcessor 各个实现类的 postProcessBeanFactory(factory) 方法
// 例如:ConfigurationClassPostProcessor 会扫描 <context:component-scan/> 和 @SpringBootApplication(scanBasePackages = "") 中的Component,并且将 @Configuration 类中的 @Bean register 到 BeanFactory 中
// 扩展例如:MyBatis MapperScannerConfigurer 和 MapperScannerRegistrar,扫描Mapper register 到 BeanFactory 中
invokeBeanFactoryPostProcessors(beanFactory);

// Register bean processors that intercept bean creation.
// 注册 BeanPostProcessor 的实现类,不同于刚刚的 BeanFactoryPostProcessor
// BeanPostProcessor 接口两个方法 postProcessBeforeInitialization 和 postProcessAfterInitialization 会在 Bean 初始化之前和之后调用
// 这边 Bean 还没初始化,下面的 finishBeanFactoryInitialization 才是真正的初始化方法
registerBeanPostProcessors(beanFactory);

// Initialize message source for this context.
// 初始化当前 ApplicationContext 的 MessageSource,解析消息的策略接口,用于支持消息的国际化和参数化
// Spring 两个开箱即用的实现 ResourceBundleMessageSource 和 ReloadableResourceBundleMessageSource
initMessageSource();

// Initialize event multicaster for this context.
// 初始化当前 ApplicationContext 的事件广播器
initApplicationEventMulticaster();

// Initialize other special beans in specific context subclasses.
// 典型模板方法
// 子类可以在实例化 bean 之前,做一些初始化工作,SpringBoot 会在这边启动 Web 服务
onRefresh();

// Check for listener beans and register them.
// 向 initApplicationEventMulticaster() 初始化的 applicationEventMulticaster 注册事件监听器,就是实现 ApplicationListener 接口类
// 观察者模式,例如实现了 ApplicationEvent,通过 ApplicationEventPublisher#publishEvent(),可以通知到各个 ApplicationListener#onApplicationEvent
registerListeners();

// Instantiate all remaining (non-lazy-init) singletons.
// 初始化所有的 singletons bean(lazy-init 的除外)
// Spring bean 初始化核心方法
finishBeanFactoryInitialization(beanFactory);

// Last step: publish corresponding event.
// ApplicationEventPublisher#publishEvent() 初始化完成(ContextRefreshedEvent)事件
finishRefresh();
}

catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}

// Destroy already created singletons to avoid dangling resources.
// destroy 已经创建的 singleton 避免占用资源
destroyBeans();

// Reset 'active' flag.
// 重置'有效'标志
cancelRefresh(ex);

// Propagate exception to caller.
throw ex;
}

finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
// 重置Spring核心中的常见内省缓存,因为可能不再需要单例bean的元数据了...
resetCommonCaches();
}
}
}

整个refresh方法中,我的理解就是在围绕bean在给bean提供环境,其中bean整个运转的生命周期。下面排了下整个方法中包括的内容:

  1. prepareRefresh();
  2. ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
  3. prepareBeanFactory(beanFactory);
  4. postProcessBeanFactory(beanFactory);
  5. invokeBeanFactoryPostProcessors(beanFactory);
  6. registerBeanPostProcessors(beanFactory);
  7. initMessageSource();
  8. initApplicationEventMulticaster();
  9. onRefresh();
  10. registerListeners();
  11. finishBeanFactoryInitialization(beanFactory);
  12. finishRefresh();
  13. destroyBeans();
  14. cancelRefresh(ex);
  15. resetCommonCaches();

刺激时刻来了,可以开始一个个解析上面的方法了,刺激!!!。

prepareRefresh()

这个是refresh()方法的第一步,准备更新上下文,设置开始时间,标记活动标志,初始化配置文件中的占位符。

/**
* Prepare this context for refreshing, setting its startup date and
* active flag as well as performing any initialization of property sources.
* 准备此上下文以进行刷新、设置其启动日期和活动标志以及执行任何属性源的初始化。
*/
protected void prepareRefresh() {
// Switch to active.
this.startupDate = System.currentTimeMillis();
this.closed.set(false);
this.active.set(true);

if (logger.isDebugEnabled()) {
if (logger.isTraceEnabled()) {
logger.trace("Refreshing " + this);
}
else {
logger.debug("Refreshing " + getDisplayName());
}
}

// 初始化上下文环境中的任何占位符属性源。
initPropertySources();

// Validate that all properties marked as required are resolvable:
// see ConfigurablePropertyResolver#setRequiredProperties
//验证标记为必需的所有属性都是可解析的
getEnvironment().validateRequiredProperties();

// Store pre-refresh ApplicationListeners...
if (this.earlyApplicationListeners == null) {
this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
}
else {
// Reset local application listeners to pre-refresh state.
this.applicationListeners.clear();
this.applicationListeners.addAll(this.earlyApplicationListeners);
}

// Allow for the collection of early ApplicationEvents,
// to be published once the multicaster is available...
this.earlyApplicationEvents = new LinkedHashSet<>();
}

obtainFreshBeanFactory()

前期方法都是在进行准备工作,obtainFreshBeanFactory是告诉子类刷新内部 bean 工厂,返回一个BeanFactory,相当于创建一个工程对象。

/**
* Tell the subclass to refresh the internal bean factory.
* @return the fresh BeanFactory instance
* @see #refreshBeanFactory()
* @see #getBeanFactory()
*/
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
refreshBeanFactory();
return getBeanFactory();
}
/**
* This implementation performs an actual refresh of this context's underlying
* bean factory, shutting down the previous bean factory (if any) and
* initializing a fresh bean factory for the next phase of the context's lifecycle.
*/
@Override
protected final void refreshBeanFactory() throws BeansException {
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
// 1. createBeanFactory(); 为此上下文创建内部 BeanFactory
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());

// 2. customizeBeanFactory(beanFactory);
// 定制 BeanFactory,是否允许 BeanDefinition 覆盖、是否允许循环引用
customizeBeanFactory(beanFactory);

// 3. loadBeanDefinitions(beanFactory);
// 通过 BeanDefinitionReader 解析 xml 文件,解析封装信息到 BeanDefinition,并将其 register 到 BeanFactory 中
loadBeanDefinitions(beanFactory);

this.beanFactory = beanFactory;
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}

prepareBeanFactory(beanFactory)

在obtainFreshBeanFactory创建了BeanFactory对象,prepareBeanFactory()方法是对BeanFactory对象的属性包装,这个方法主要处理内容:

  1. 设置 BeanFactory 的类加载器
  2. 添加几个 BeanPostProcessor,
  3. 实例化几个特殊的 bean
/**
* Configure the factory's standard context characteristics,
* such as the context's ClassLoader and post-processors.
* @param beanFactory the BeanFactory to configure
*/
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// 1. 设置 BeanFactory 的类加载器
// 2. 添加几个 BeanPostProcessor,
// 3. 实例化几个特殊的 bean

//告诉内部bean工厂使用上下文的类加载器等。
beanFactory.setBeanClassLoader(getClassLoader());
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

// 使用上下文回调配置bean工厂。
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);

// BeanFactory interface not registered as resolvable type in a plain factory.在普通工厂中没有注册为可解析类型。
// MessageSource registered (and found for autowiring) as a bean.消息源注册为bean(并找到用于自动连接)。
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this);

// Register early post-processor for detecting inner beans as ApplicationListeners.
//将用于检测内部bean的早期后处理器注册为应用程序监听器。
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

// Detect a LoadTimeWeaver and prepare for weaving, if found.
if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
// Set a temporary ClassLoader for type matching.
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}

// Register default environment beans.
if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
}
if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
}
if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
}
}

postProcessBeanFactory(beanFactory)

在 AbstractApplicationContext#postProcessBeanFactory 为空实现,留给子类做扩展,不同 ApplicationContext 实现不同,不作详细描述

/**
* Modify the application context's internal bean factory after its standard
* initialization. All bean definitions will have been loaded, but no beans
* will have been instantiated yet. This allows for registering special
* BeanPostProcessors etc in certain ApplicationContext implementations.
* @param beanFactory the bean factory used by the application context
*/
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
}

invokeBeanFactoryPostProcessors(beanFactory)

postProcessBeanFactory()方法构建了BeanFactory的PostProcessors,invokeBeanFactoryPostProcessors()方法则是调用postProcessBeanFactory()方法所准备的PostProcessors。

/**
* Instantiate and invoke all registered BeanFactoryPostProcessor beans,
* respecting explicit order if given.
* <p>Must be called before singleton instantiation.
*/
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());

// Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
// (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
}

obtainFreshBeanFactory(),prepareBeanFactory(),postProcessBeanFactory(),invokeBeanFactoryPostProcessors()等4个方法是对BeanFactory做处理。

registerBeanPostProcessors(beanFactory)

这个对于Bean 的PostProcessor的bean进行注册,以及实例化。这句话不好读,这里面有一个PostProcessor他是对于bean进行增强处理的,但是PostProcessor也是以bean的形式进行运转的。

/**
* Instantiate and register all BeanPostProcessor beans,
* respecting explicit order if given.
* <p>Must be called before any instantiation of application beans.
*/
protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);
}

initMessageSource()

初始化当前 ApplicationContext 的 MessageSource,解析消息的策略接口,用于支持消息的国际化和参数化

/**
* Initialize the MessageSource.
* Use parent's if none defined in this context.
*/
protected void initMessageSource() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) {
this.messageSource = beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.class);
// Make MessageSource aware of parent MessageSource.
if (this.parent != null && this.messageSource instanceof HierarchicalMessageSource) {
HierarchicalMessageSource hms = (HierarchicalMessageSource) this.messageSource;
if (hms.getParentMessageSource() == null) {
// Only set parent context as parent MessageSource if no parent MessageSource
// registered already.
hms.setParentMessageSource(getInternalParentMessageSource());
}
}
if (logger.isTraceEnabled()) {
logger.trace("Using MessageSource [" + this.messageSource + "]");
}
}
else {
// Use empty MessageSource to be able to accept getMessage calls.
DelegatingMessageSource dms = new DelegatingMessageSource();
dms.setParentMessageSource(getInternalParentMessageSource());
this.messageSource = dms;
beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource);
if (logger.isTraceEnabled()) {
logger.trace("No '" + MESSAGE_SOURCE_BEAN_NAME + "' bean, using [" + this.messageSource + "]");
}
}
}

initApplicationEventMulticaster()

初始化当前 ApplicationContext 的事件广播器。

/**
* Initialize the ApplicationEventMulticaster.
* Uses SimpleApplicationEventMulticaster if none defined in the context.
* @see org.springframework.context.event.SimpleApplicationEventMulticaster
*/
protected void initApplicationEventMulticaster() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
this.applicationEventMulticaster =
beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
if (logger.isTraceEnabled()) {
logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
}
}
else {
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
if (logger.isTraceEnabled()) {
logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " +
"[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");
}
}
}

onRefresh()

这是一个空的方法,集成的实现类可以按照自己的处理方式进行特殊处理,典型的模板模式

/**
* Template method which can be overridden to add context-specific refresh work.
* Called on initialization of special beans, before instantiation of singletons.
* <p>This implementation is empty.
* @throws BeansException in case of errors
* @see #refresh()
*/
protected void onRefresh() throws BeansException {
// For subclasses: do nothing by default.
}

registerListeners()

registerListeners()方法是呼应initApplicationEventMulticaster()方法,initApplicationEventMulticaster()进行事件的广播,而registerListeners()方法则是进行时间的监听,例如aop代理监听也在这里进行初试化处理。

/**
* Add beans that implement ApplicationListener as listeners.
* Doesn't affect other listeners, which can be added without being beans.
*/
protected void registerListeners() {
// Register statically specified listeners first.
for (ApplicationListener<?> listener : getApplicationListeners()) {
getApplicationEventMulticaster().addApplicationListener(listener);
}

// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let post-processors apply to them!
String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
for (String listenerBeanName : listenerBeanNames) {
getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
}

// Publish early application events now that we finally have a multicaster...
Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
this.earlyApplicationEvents = null;
if (!CollectionUtils.isEmpty(earlyEventsToProcess)) {
for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
getApplicationEventMulticaster().multicastEvent(earlyEvent);
}
}
}

finishBeanFactoryInitialization(beanFactory)

这个方法是 核心中的核心内容,这个方法进行了bean的创建,初始化和实例化,这个在后面代码实际操作,打断点时候核心讲解的内容。

/**
* Finish the initialization of this context's bean factory,
* initializing all remaining singleton beans.
*/
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
// Initialize conversion service for this context.
if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
beanFactory.setConversionService(
beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
}

// Register a default embedded value resolver if no BeanFactoryPostProcessor
// (such as a PropertySourcesPlaceholderConfigurer bean) registered any before:
// at this point, primarily for resolution in annotation attribute values.
if (!beanFactory.hasEmbeddedValueResolver()) {
beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
}

// Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
for (String weaverAwareName : weaverAwareNames) {
getBean(weaverAwareName);
}

// Stop using the temporary ClassLoader for type matching.
beanFactory.setTempClassLoader(null);

// Allow for caching all bean definition metadata, not expecting further changes.
beanFactory.freezeConfiguration();

// Instantiate all remaining (non-lazy-init) singletons.
beanFactory.preInstantiateSingletons();
}

finishRefresh()

这个是refresh方法的收尾,进行容器的发布。

/**
* Finish the refresh of this context, invoking the LifecycleProcessor's
* onRefresh() method and publishing the
* {@link org.springframework.context.event.ContextRefreshedEvent}.
*/
protected void finishRefresh() {
// Clear context-level resource caches (such as ASM metadata from scanning).
clearResourceCaches();

// Initialize lifecycle processor for this context.
initLifecycleProcessor();

// Propagate refresh to lifecycle processor first.
getLifecycleProcessor().onRefresh();

// Publish the final event.
publishEvent(new ContextRefreshedEvent(this));

// Participate in LiveBeansView MBean, if active.
LiveBeansView.registerApplicationContext(this);
}

refresh是集成ConfigurableApplicationContext接口对应的refresh()方法。

这篇refresh的介绍是相对比较粗的内容,没有详细去拆解,因为我认为真的详细拆解了,可能看了 这边文章也记不住所以就大概介绍了下。

如果真的想把这里深入了解下,我的方式是通过代码打断点去看,一点点往下走,也不用一步步看,前面几次先看大概,后面再跟进自己感兴趣或者意向高的内容再去了解下,多跑断点,一点点就清晰了。后面会详细将跑断点的过程,先补充基础,在基础 上进行实操,这时候会有共鸣!


标签:NAME,beanFactory,--,spring,BEAN,refresh,bean,源码,context
From: https://blog.51cto.com/u_15969474/6068642

相关文章

  • 测试ChatGPT:web接口
    需求描述:请给我一个flask接口用于获取后端服务器上的静态资源 对话内容:  1fromflaskimportFlask,send_from_directory2app=Flask(__name__)34......
  • 智能通信网关管理设备(借助工业智能网关实现工业设备在线监控和维护)
    方案背景工厂的设备都需要定时检修维护,保障稳定运行和安全生产。无论是日常检查还是故障维护,都需要花费相当多的人力、物力和资金,也需要面对停工维护带来的损失。在传统维护......
  • 圆锥曲线 / conic section の 推导 / proof
    #####椭圆/eclipse-equation/公式:$\frac{x^2}{a^2}+\frac{y^2}{b^2}=1\/\\frac{y^2}{a^2}+\frac{x^2}{b^2}=1\quad\left(a>b>0\right)$-顶点:$(\pma,0),(0,\pmb......
  • flex 布局 item 子元素层级问题
    原始状态<html><head><metacharset="utf-8"><style>#main{width:300px;height:300px;border:1pxsolidblack;display:flex;flex-direction:colum......
  • Windows加装新固态硬盘设置过程
    开机后打开资源管理器,此电脑-右键-管理-磁盘管理打开后会自动弹出磁盘初始化界面(图略),这里有两个选项:MBR和GPT。MBR应用较广泛,允许通过LegacyBIOS启动,但支持分区的大小及......
  • vue3中对于/deep/和::v-deep的警告信息处理
    目前发现两处警告信息:::v-deepusageasacombinatorhasbeendeprecated.Use:deep()instead.the>>>and/deep/combinatorshavebeendeprecated.Use:deep()......
  • QWidget设置成模态对话框并弹框显示
    正确的做法: 1、FormProcessRoi*form=newFormProcessRoi(this);//只能用指针,不能实例化为对象//Qt::NonModal不阻塞//Qt::WindowModal阻塞父窗口,所有祖先窗......
  • Vue2 项目中添加 vite
    正常创建Vue2项目使用命令方式vuecreateprojectname或使用图形方式vueui安装vite相关组件安装组件,此组件是开发依赖包。npminstallvitevite-plugin-vue2......
  • 先序构造二叉树、层次遍历输出
    #include<iostream>#include<queue>usingnamespacestd;//树结构定义typedefstructnode{charval;structnode*left;structnode*right;}Tre......
  • 位运算与二进制表示集合
    位运算与二进制表示集合位运算运算符运算运算符数学符号表示解释与&&、\(and\)只有两个对应位都为\(1\)时才为\(1\)或\(|\)\(|\)、\(or\)只要两......