• SpringBoot启动中,BeanDefinition的加载(一)AnnotatedBeanDefinitionReader 注解BeanDefinition的注册



    在SpringApplication的run方法中,调用了prepareContext方法,prepareContext方法用来准备上下文,即加载上下文时需要的资源。在方法的最后,加载了资源路径和加载器的load()方法,使用加载器从资源文件中注册BeanDefinition。
    此篇我们看一下注解类型的BeanDefinition加载过程

    SpringApplication.load()

    public class SpringApplication {
    	//向上下文加载bean
    	protected void load(ApplicationContext context, Object[] sources) {
    		if (logger.isDebugEnabled()) {
    			logger.debug("Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
    		}
    		//创建BeanDefinitionLoader加载器
    		BeanDefinitionLoader loader = createBeanDefinitionLoader(getBeanDefinitionRegistry(context), sources);
    		if (this.beanNameGenerator != null) {
    			loader.setBeanNameGenerator(this.beanNameGenerator);
    		}
    		if (this.resourceLoader != null) {
    			loader.setResourceLoader(this.resourceLoader);
    		}
    		if (this.environment != null) {
    			loader.setEnvironment(this.environment);
    		}
    		loader.load();
    	}
    	protected BeanDefinitionLoader createBeanDefinitionLoader(BeanDefinitionRegistry registry, Object[] sources) {
    		return new BeanDefinitionLoader(registry, sources);
    	}
    }
    

    BeanDefinitionLoader

    BeanDefinitionLoader是一个门面类:在类构造函数中,构造了AnnotatedBeanDefinitionReader、XmlBeanDefinitionReader和ClassPathBeanDefinitionScanner三个类型的读取类。并在ClassPathBeanDefinitionScanner中添加了一个类排除过滤器。

    /**
    *从给定的资源文件加载Bean Definition,包括XML和java config.是AnnotatedBeanDefinitionReader, XmlBeanDefinitionReader 
    *and ClassPathBeanDefinitionScanner的门面类。
    */
    class BeanDefinitionLoader {
    	BeanDefinitionLoader(BeanDefinitionRegistry registry, Object... sources) {
    		Assert.notNull(registry, "Registry must not be null");
    		Assert.notEmpty(sources, "Sources must not be empty");
    		this.sources = sources;
    		this.annotatedReader = new AnnotatedBeanDefinitionReader(registry);
    		this.xmlReader = (XML_ENABLED ? new XmlBeanDefinitionReader(registry) : null);
    		this.groovyReader = (isGroovyPresent() ? new GroovyBeanDefinitionReader(registry) : null);
    		this.scanner = new ClassPathBeanDefinitionScanner(registry);
    		this.scanner.addExcludeFilter(new ClassExcludeFilter(sources));
    	}
    
     	//加载所有的资源到读取器中
     	void load() {
    		for (Object source : this.sources) {
    			load(source);
    		}
    	}
     	//此处使用重载的方式,加载不同类型的资源文件,此处的资源类型为Class
     	private void load(Object source) {
    		Assert.notNull(source, "Source must not be null");
    		if (source instanceof Class<?>) {
    			load((Class<?>) source);
    			return;
    		}
    		if (source instanceof Resource) {
    			load((Resource) source);
    			return;
    		}
    		if (source instanceof Package) {
    			load((Package) source);
    			return;
    		}
    		if (source instanceof CharSequence) {
    			load((CharSequence) source);
    			return;
    		}
    		throw new IllegalArgumentException("Invalid source type " + source.getClass());
    	}
    
    	private void load(Class<?> source) {
    		if (isGroovyPresent() && GroovyBeanDefinitionSource.class.isAssignableFrom(source)) {
    			// Any GroovyLoaders added in beans{} DSL can contribute beans here
    			GroovyBeanDefinitionSource loader = BeanUtils.instantiateClass(source, GroovyBeanDefinitionSource.class);
    			((GroovyBeanDefinitionReader) this.groovyReader).beans(loader.getBeans());
    		}
    		//判断类是否符合条件
    		if (isEligible(source)) {
    			//使用注解读取器注册资源
    			this.annotatedReader.register(source);
    		}
    	}
    	//不是匿名类、Groovy闭包和有构造函数
    	private boolean isEligible(Class<?> type) {
    		return !(type.isAnonymousClass() || isGroovyClosure(type) || hasNoConstructors(type));
    	}
    }
    

    AnnotatedBeanDefinitionReader annotatedReader

    执行完doRegisterBean方法,就将一个完成的BeanDefinition注册了进去

    public class AnnotatedBeanDefinitionReader {
    
    	//beanName生成器
    	private BeanNameGenerator beanNameGenerator = AnnotationBeanNameGenerator.INSTANCE;
    
    	public void register(Class<?>... componentClasses) {
    		for (Class<?> componentClass : componentClasses) {
    			registerBean(componentClass);
    		}
    	}
    	//从给定的Bean中注册bean,推导元数据信息从声明的类注解上
    	public void registerBean(Class<?> beanClass) {
    		doRegisterBean(beanClass, null, null, null, null);
    	}
    
    	/*
    	*beanClass:bean class;     name:bean执行的显式名称
    	*qualifiers:注解限定符         supplier:创建bean实例之后的回调功能
    	*customizers:一个或多个回调函数用于定制工厂的BeanDefinition,例如设置lazy-init或primary标志
    	*/
    	private <T> void doRegisterBean(Class<T> beanClass, @Nullable String name,
    			@Nullable Class<? extends Annotation>[] qualifiers, @Nullable Supplier<T> supplier,
    			@Nullable BeanDefinitionCustomizer[] customizers) {
    		//首先根据传入的首要类构建一个AnnotatedGenericBeanDefinition:一般注解型BeanDefinition
    		AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
    		if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
    			return;
    		}
    		//设置实例化回调器
    		abd.setInstanceSupplier(supplier);
    		//解析范围元数据
    		ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
    		//scopeMetadata.getScopeName() = singleton
    		abd.setScope(scopeMetadata.getScopeName());
    		String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
    		//处理普通BeanDefinition
    		AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
    		//设置限定符属性
    		if (qualifiers != null) {
    			for (Class<? extends Annotation> qualifier : qualifiers) {
    				if (Primary.class == qualifier) {
    					abd.setPrimary(true);
    				}
    				else if (Lazy.class == qualifier) {
    					abd.setLazyInit(true);
    				}
    				else {
    					abd.addQualifier(new AutowireCandidateQualifier(qualifier));
    				}
    			}
    		}
    		if (customizers != null) {
    			for (BeanDefinitionCustomizer customizer : customizers) {
    				customizer.customize(abd);
    			}
    		}
    		//根据abd构建一个BeanDefinitionHolder
    		BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
    		//根据scope注解,判断是否生成范围域代理类
    		definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
    		//调用工具类将definitionHolder注册到工厂容器
    		BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
    	}
    }
    

    qualifier的属性应用

    AnnotatedGenericBeanDefinition

    public class AnnotatedGenericBeanDefinition extends GenericBeanDefinition implements AnnotatedBeanDefinition {
    
    	public AnnotatedGenericBeanDefinition(Class<?> beanClass) {
    		setBeanClass(beanClass);
    		this.metadata = AnnotationMetadata.introspect(beanClass);
    	}
    }
    
    • GenericBeanDefinition
    public class GenericBeanDefinition extends AbstractBeanDefinition {
    
    }
    
    • AbstractBeanDefinition
    public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccessor
    		implements BeanDefinition, Cloneable {
    	//织入Bean属性自动装配策略  名称、类型、构造函数、自省
    	public static final int AUTOWIRE_NO = AutowireCapableBeanFactory.AUTOWIRE_NO;
    	public static final int AUTOWIRE_BY_NAME = AutowireCapableBeanFactory.AUTOWIRE_BY_NAME;
    	public static final int AUTOWIRE_BY_TYPE = AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE;
    	public static final int AUTOWIRE_CONSTRUCTOR = AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR;
    	public static final int AUTOWIRE_AUTODETECT = AutowireCapableBeanFactory.AUTOWIRE_AUTODETECT;
    
    	private volatile Object beanClass;
    
    	public void setBeanClass(@Nullable Class<?> beanClass) {
    		this.beanClass = beanClass;
    	}
    }
    
    AnnotationMetadata
    public interface AnnotationMetadata extends ClassMetadata, AnnotatedTypeMetadata {
    	//工厂方法使用标准反射为给定类创建一个新的AnnotationMetadata实例
    	static AnnotationMetadata introspect(Class<?> type) {
    		return StandardAnnotationMetadata.from(type);
    	}
    }
    
    
    • StandardAnnotationMetadata
    public class StandardAnnotationMetadata extends StandardClassMetadata implements AnnotationMetadata {
    	static AnnotationMetadata from(Class<?> introspectedClass) {
    		return new StandardAnnotationMetadata(introspectedClass, true);
    	}
    
    	public StandardAnnotationMetadata(Class<?> introspectedClass, boolean nestedAnnotationsAsMap) {
    		super(introspectedClass);
    		this.mergedAnnotations = MergedAnnotations.from(introspectedClass,
    				SearchStrategy.INHERITED_ANNOTATIONS, RepeatableContainers.none());
    		this.nestedAnnotationsAsMap = nestedAnnotationsAsMap;
    	}
    
    
    }
    
    • StandardClassMetadata
    public class StandardClassMetadata implements ClassMetadata {
    	//自检类
    	private final Class<?> introspectedClass;
    	public StandardClassMetadata(Class<?> introspectedClass) {
    		Assert.notNull(introspectedClass, "Class must not be null");
    		//设置自检类为首要类
    		this.introspectedClass = introspectedClass;
    	}
    }
    
    

    AnnotationBeanNameGenerator

    public class AnnotationBeanNameGenerator implements BeanNameGenerator {
    
    	public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
    		if (definition instanceof AnnotatedBeanDefinition) {
    			//如果beanName为空,则继续向下执行,生成bean默认名称
    			String beanName = determineBeanNameFromAnnotation((AnnotatedBeanDefinition) definition);
    			if (StringUtils.hasText(beanName)) {
    				// Explicit bean name found.
    				return beanName;
    			}
    		}
    		// Fallback: generate a unique default bean name.
    		return buildDefaultBeanName(definition, registry);
    	}
    
    	//获取注解,根据注解类型判断注解是否是模板注解(Component),并判断注解中的value是否有值,有值的话即要返回的beanName;
    	protected String determineBeanNameFromAnnotation(AnnotatedBeanDefinition annotatedDef) {
    		AnnotationMetadata amd = annotatedDef.getMetadata();
    		Set<String> types = amd.getAnnotationTypes();
    		String beanName = null;
    		for (String type : types) {
    			AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(amd, type);
    			if (attributes != null) {
    				Set<String> metaTypes = this.metaAnnotationTypesCache.computeIfAbsent(type, key -> {
    					Set<String> result = amd.getMetaAnnotationTypes(key);
    					return (result.isEmpty() ? Collections.emptySet() : result);
    				});
    				if (isStereotypeWithNameValue(type, metaTypes, attributes)) {
    					Object value = attributes.get("value");
    					if (value instanceof String) {
    						String strVal = (String) value;
    						if (StringUtils.hasLength(strVal)) {
    							if (beanName != null && !strVal.equals(beanName)) {
    								throw new IllegalStateException("Stereotype annotations suggest inconsistent " +
    										"component names: '" + beanName + "' versus '" + strVal + "'");
    							}
    							beanName = strVal;
    						}
    					}
    				}
    			}
    		}
    		return beanName;
    	}
    
    	protected String buildDefaultBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
    		return buildDefaultBeanName(definition);
    	}
    
    	protected String buildDefaultBeanName(BeanDefinition definition) {
    		String beanClassName = definition.getBeanClassName();
    		Assert.state(beanClassName != null, "No bean class name set");
    		String shortClassName = ClassUtils.getShortName(beanClassName);
    		//调用内省类,处理beanName
    		return Introspector.decapitalize(shortClassName);
    	}
    
    }
    
    

    AnnotationConfigUtils

    /**
    *实用程序类,它允许方便地注册通用的org.springframework.beans.factory.config.BeanPostProcessor
    *和org.springframework.beans.factory.config.BeanFactoryPostProcessor定义,用于基于注释的配置。
    *还注册了一个通用的org.springframework.beans.factory.support. autowireccandidateresolver。
    */
    public abstract class AnnotationConfigUtils {
    	public static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd) {
    		processCommonDefinitionAnnotations(abd, abd.getMetadata());
    	}
    
    	static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd, AnnotatedTypeMetadata metadata) {
    		AnnotationAttributes lazy = attributesFor(metadata, Lazy.class);
    		//lazy默认为空
    		if (lazy != null) {
    			abd.setLazyInit(lazy.getBoolean("value"));
    		}
    		else if (abd.getMetadata() != metadata) {
    			lazy = attributesFor(abd.getMetadata(), Lazy.class);
    			if (lazy != null) {
    				abd.setLazyInit(lazy.getBoolean("value"));
    			}
    		}
    		//Primary无标注
    		if (metadata.isAnnotated(Primary.class.getName())) {
    			abd.setPrimary(true);
    		}
    		//dependsOn 为空
    		AnnotationAttributes dependsOn = attributesFor(metadata, DependsOn.class);
    		if (dependsOn != null) {
    			abd.setDependsOn(dependsOn.getStringArray("value"));
    		}
    		//role为空
    		AnnotationAttributes role = attributesFor(metadata, Role.class);
    		if (role != null) {
    			abd.setRole(role.getNumber("value").intValue());
    		}
    		//description 为空
    		AnnotationAttributes description = attributesFor(metadata, Description.class);
    		if (description != null) {
    			abd.setDescription(description.getString("value"));
    		}
    	}
    	//判断是否为范围域生成代理类,
    	static BeanDefinitionHolder applyScopedProxyMode(
    			ScopeMetadata metadata, BeanDefinitionHolder definition, BeanDefinitionRegistry registry) {
    
    		ScopedProxyMode scopedProxyMode = metadata.getScopedProxyMode();
    		if (scopedProxyMode.equals(ScopedProxyMode.NO)) {
    			return definition;
    		}
    		boolean proxyTargetClass = scopedProxyMode.equals(ScopedProxyMode.TARGET_CLASS);
    		return ScopedProxyCreator.createScopedProxy(definition, registry, proxyTargetClass);
    	}
    }
    
    
    ScopedProxyCreator

    调用ScopedProxyCreator的createScopedProxy方法,方法内部调用ScopedProxyUtils工具类生成代理类BeanDefinitionHolder,详情可参考博客Scope注解的proxyMode的作用以及如何影响IoC容器的依赖查找

    final class ScopedProxyCreator {
    
    	private ScopedProxyCreator() {
    	}
    
    
    	public static BeanDefinitionHolder createScopedProxy(
    			BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry, boolean proxyTargetClass) {
    
    		return ScopedProxyUtils.createScopedProxy(definitionHolder, registry, proxyTargetClass);
    	}
    
    	public static String getTargetBeanName(String originalBeanName) {
    		return ScopedProxyUtils.getTargetBeanName(originalBeanName);
    	}
    
    }
    

    BeanDefinitionHolder

    public class BeanDefinitionHolder implements BeanMetadataElement {
    
    	private final BeanDefinition beanDefinition;
    
    	private final String beanName;
    
    	@Nullable
    	private final String[] aliases;
    
    	public BeanDefinitionHolder(BeanDefinition beanDefinition, String beanName) {
    		this(beanDefinition, beanName, null);
    	}
    
    	/**
    	 * Create a new BeanDefinitionHolder.
    	 * @param beanDefinition 被装饰的BeanDefinition
    	 * @param beanName the name of the bean, as specified for the bean definition
    	 * @param aliases alias names for the bean, or {@code null} if none
    	 */
    	public BeanDefinitionHolder(BeanDefinition beanDefinition, String beanName, @Nullable String[] aliases) {
    		Assert.notNull(beanDefinition, "BeanDefinition must not be null");
    		Assert.notNull(beanName, "Bean name must not be null");
    		this.beanDefinition = beanDefinition;
    		this.beanName = beanName;
    		this.aliases = aliases;
    	}
    
    }
    

    BeanDefinitionReaderUtils

    调用BeanDefinitionReaderUtils 的registerBeanDefinition,注册BeanDefinition,内部调用ApplicationContext的registerBeanDefinition方法,判断别名是否为空,如果不为空,则进行别名注册

    public abstract class BeanDefinitionReaderUtils {
    	public static void registerBeanDefinition(
    			BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
    			throws BeanDefinitionStoreException {
    
    		// Register bean definition under primary name.
    		String beanName = definitionHolder.getBeanName();
    		registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
    
    		// Register aliases for bean name, if any.
    		String[] aliases = definitionHolder.getAliases();
    		if (aliases != null) {
    			for (String alias : aliases) {
    				registry.registerAlias(beanName, alias);
    			}
    		}
    	}
    
    }
    
    • GenericApplicationContext
      GenericApplicationContext内部调用了DefaultListableBeanFactory 的registerBeanDefinition方法
    public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry {
    	private final DefaultListableBeanFactory beanFactory;
    	@Override
    	public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
    			throws BeanDefinitionStoreException {
    
    		this.beanFactory.registerBeanDefinition(beanName, beanDefinition);
    	}
    	//别名注册
    	@Override
    	public void registerAlias(String beanName, String alias) {
    		this.beanFactory.registerAlias(beanName, alias);
    	}
    }
    
    • SimpleAliasRegistry
      使用map缓存别名和beanName之间的关系,在存储之前会检查别名是否循环引用
    public class SimpleAliasRegistry implements AliasRegistry {
    	public void registerAlias(String name, String alias) {
    	
    		synchronized (this.aliasMap) {
    			if (alias.equals(name)) {
    				this.aliasMap.remove(alias);
    				if (logger.isDebugEnabled()) {
    					logger.debug("Alias definition '" + alias + "' ignored since it points to same name");
    				}
    			}
    			else {
    				String registeredName = this.aliasMap.get(alias);
    				if (registeredName != null) {
    					if (registeredName.equals(name)) {
    						// An existing alias - no need to re-register
    						return;
    					}
    				    ......
    				}
    				checkForAliasCircle(name, alias);
    				this.aliasMap.put(alias, name);
    				if (logger.isTraceEnabled()) {
    					logger.trace("Alias definition '" + alias + "' registered for name '" + name + "'");
    				}
    			}
    		}
    	}
    }
    
    • DefaultListableBeanFactory
    public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
    		implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
    
    	public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
    			throws BeanDefinitionStoreException {
    
    		Assert.hasText(beanName, "Bean name must not be empty");
    		Assert.notNull(beanDefinition, "BeanDefinition must not be null");
    		//如果beanDefinition 是AbstractBeanDefinition类型
    		if (beanDefinition instanceof AbstractBeanDefinition) {
    			try {
    				//对beanDefinition进行验证
    				((AbstractBeanDefinition) beanDefinition).validate();
    			}
    			catch (BeanDefinitionValidationException ex) {
    				throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
    						"Validation of bean definition failed", ex);
    			}
    		}
    		//从容器中获取BeanDefinition 
    		BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
    		if (existingDefinition != null) {
    			if (!isAllowBeanDefinitionOverriding()) {
    				throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
    			}
    			else if (existingDefinition.getRole() < beanDefinition.getRole()) {
    				// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
    				if (logger.isInfoEnabled()) {
    					logger.info("Overriding user-defined bean definition for bean '" + beanName +
    							"' with a framework-generated bean definition: replacing [" +
    							existingDefinition + "] with [" + beanDefinition + "]");
    				}
    			}
    			else if (!beanDefinition.equals(existingDefinition)) {
    				if (logger.isDebugEnabled()) {
    					logger.debug("Overriding bean definition for bean '" + beanName +
    							"' with a different definition: replacing [" + existingDefinition +
    							"] with [" + beanDefinition + "]");
    				}
    			}
    			else {
    				if (logger.isTraceEnabled()) {
    					logger.trace("Overriding bean definition for bean '" + beanName +
    							"' with an equivalent definition: replacing [" + existingDefinition +
    							"] with [" + beanDefinition + "]");
    				}
    			}
    			this.beanDefinitionMap.put(beanName, beanDefinition);
    		}
    		//如果BeanDefinition 为空,并且BeanDefinition 不再创建过程中,进入else,将beanDefinition放入容器
    		else {
    			if (hasBeanCreationStarted()) {
    				// Cannot modify startup-time collection elements anymore (for stable iteration)
    				synchronized (this.beanDefinitionMap) {
    					this.beanDefinitionMap.put(beanName, beanDefinition);
    					List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
    					updatedDefinitions.addAll(this.beanDefinitionNames);
    					updatedDefinitions.add(beanName);
    					this.beanDefinitionNames = updatedDefinitions;
    					removeManualSingletonName(beanName);
    				}
    			}
    			else {
    				// Still in startup registration phase
    				this.beanDefinitionMap.put(beanName, beanDefinition);
    				this.beanDefinitionNames.add(beanName);
    				removeManualSingletonName(beanName);
    			}
    			this.frozenBeanDefinitionNames = null;
    		}
    
    		if (existingDefinition != null || containsSingleton(beanName)) {
    			resetBeanDefinition(beanName);
    		}
    		else if (isConfigurationFrozen()) {
    			clearByTypeCache();
    		}
    	}
    	//调用lambda表达式,对处在手动创建的beanName进行处理
    	private void removeManualSingletonName(String beanName) {
    		updateManualSingletonNames(set -> set.remove(beanName), set -> set.contains(beanName));
    	}
    
    	private void updateManualSingletonNames(Consumer<Set<String>> action, Predicate<Set<String>> condition) {
    		if (hasBeanCreationStarted()) {
    			// Cannot modify startup-time collection elements anymore (for stable iteration)
    			synchronized (this.beanDefinitionMap) {
    				if (condition.test(this.manualSingletonNames)) {
    					Set<String> updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames);
    					action.accept(updatedSingletons);
    					this.manualSingletonNames = updatedSingletons;
    				}
    			}
    		}
    		else {
    			// Still in startup registration phase
    			if (condition.test(this.manualSingletonNames)) {
    				action.accept(this.manualSingletonNames);
    			}
    		}
    	}
    }
    
    

    AbstractBeanDefinitionReader xmlReader

    ClassPathBeanDefinitionScanner scanner

    工具类

    Introspector 自省类

    public class Introspector {
        
        /*
        *工具方法获取一个字符串并将其转换为普通Java变量名大写。这通常意味着将第一个字符从大写字母
        *转换为小写字母,但在(不寻常的)特殊情况下,当有多个字符且第一个和第二个字符都是大写字母时,
        *我们不去管它
        */
        public static String decapitalize(String name) {
            if (name == null || name.length() == 0) {
                return name;
            }
            if (name.length() > 1 && Character.isUpperCase(name.charAt(1)) &&
                            Character.isUpperCase(name.charAt(0))){
                return name;
            }
            char chars[] = name.toCharArray();
            chars[0] = Character.toLowerCase(chars[0]);
            return new String(chars);
        }
    }
    
  • 相关阅读:
    POJ 1330 Nearest Common Ancestors(LCA Tarjan算法)
    LCA 最近公共祖先 (模板)
    线段树,最大值查询位置
    带权并查集
    转负二进制
    UVA 11437 Triangle Fun
    UVA 11488 Hyper Prefix Sets (字典树)
    UVALive 3295 Counting Triangles
    POJ 2752 Seek the Name, Seek the Fame (KMP)
    UVA 11584 Partitioning by Palindromes (字符串区间dp)
  • 原文地址:https://www.cnblogs.com/nangonghui/p/15673471.html
Copyright © 2020-2023  润新知