Spring源码解析之推断构造方法

Spring推断构造方法

贴个测试代码直接开干,这只是个样例,其他情况自行分析

@Component
public class OrderService {

	public OrderService() {
		System.out.println("无参构造方法");
	}

	@Autowired(required = false)
	public OrderService(UserService userService) {
		System.out.println("一个参数的构造方法");
	}

	@Autowired(required = false)
	public OrderService(String userName, String passWord) {
		System.out.println("两个参数的构造方法");
	}
}

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBeanInstance

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {

		// 加载类
		// Make sure bean class is actually resolved at this point.
		Class<?> beanClass = resolveBeanClass(mbd, beanName);

		// 确保class不为空,并且访问权限为public
		if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
			throw new BeanCreationException(mbd.getResourceDescription(), beanName,
					"Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
		}

		// 配置的一种特殊的callback回调方法,通过这个callback创建bean
		// 检查BeanDefinition是否包含了一个Supplier
		Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
		if (instanceSupplier != null) {
			// 如果有就直接调用Supplier的get方法得到一个对象直接返回
			return obtainFromSupplier(instanceSupplier, beanName);
		}

		// 通过工厂方法创建
		if (mbd.getFactoryMethodName() != null) {
			// 如果BeanDefinition中存在FactoryMethodName,那么调用工厂方法得到一个bean对象并返回
			return instantiateUsingFactoryMethod(beanName, mbd, args);
		}

		// 一个类可能有多个构造器,所以Spring得根据参数个数、类型确定需要调用的构造器
		// 在使用构造器创建实例后,Spring会将解析过后确定下来的构造器或工厂方法保存在缓存中,避免再次创建相同bean时再次解析
		// Shortcut when re-creating the same bean...
		boolean resolved = false;
		boolean autowireNecessary = false;
		if (args == null) {
			synchronized (mbd.constructorArgumentLock) {
				if (mbd.resolvedConstructorOrFactoryMethod != null) {
					// 已经解析过class的构造器
					resolved = true;
					autowireNecessary = mbd.constructorArgumentsResolved;
				}
			}
		}
		if (resolved) {
			// 已经解析过class的构造器,使用已经解析好的构造器
			if (autowireNecessary) {
				// 如果BeanDefinition中已经构造过
				// 构造函数自动注入
				// 自动装配构造函数,俗称推断构造方法
				return autowireConstructor(beanName, mbd, null, null);
			}
			else {
				// 使用默认构造器
				return instantiateBean(beanName, mbd);
			}
		}

		// TODO 推断构造方法
		// 需要根据参数解析、确定构造函数
		// 寻找当前实例化的bean中构造器是否有@Autowire注解
		// Candidate constructors for autowiring?
		Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);

		// 解析的构造器不为空 || 注入类型为构造函数自动注入 || beanDefinition指定了构造方法参数值 || getBean时指定了构造方法参数
		if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
				mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {

			// 到这里可能找到了多个构造方法,还要决定到底用哪个进行反射初始化
			return autowireConstructor(beanName, mbd, ctors, args);
		}

		// 默认构造的首选构造函数?
		// Preferred constructors for default construction?
		ctors = mbd.getPreferredConstructors();
		if (ctors != null) {
			return autowireConstructor(beanName, mbd, ctors, null);
		}

		// 无需特殊处理:只需使用默认的无参构造函数
		// No special handling: simply use no-arg constructor.
		return instantiateBean(beanName, mbd);
	}

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#determineConstructorsFromBeanPostProcessors

protected Constructor<?>[] determineConstructorsFromBeanPostProcessors(@Nullable Class<?> beanClass, String beanName)
			throws BeansException {

		// 装配beanPostProcessor的时候会判断其类型并设置 hasInstantiationAwareBeanPostProcessors 属性, 符合条件才去找构造函数
		if (beanClass != null && hasInstantiationAwareBeanPostProcessors()) {

			// getBeanPostProcessors拿到beanFactory中的所有BeanPostProcessor接口,找到一个合格的构造函数
			for (BeanPostProcessor bp : getBeanPostProcessors()) {
				if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
					SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;

					// 获取有autowire注解的构造函数 找到合格的构造函数
					// AutowiredAnnotationBeanPostProcessor.determineCandidateConstructors
					Constructor<?>[] ctors = ibp.determineCandidateConstructors(beanClass, beanName);
					if (ctors != null) {
						return ctors;
					}
				}
			}
		}
		return null;
	}

org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#determineCandidateConstructors

public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, final String beanName)
			throws BeanCreationException {

		// @Lookup标识的属性每次调用都会被重新初始化,
		// 有些场景下原型类型的Bean就需要这样做,否则每个Bean只会在spring容器初始化的时候创建一次,
		// 但是如果在一个单例的Bean中注入了一个原型的Bean,这样的话原本原型的Bean就相当于变成了一个单例的Bean失去了原有的意义,
		// 这时就需要@Lookup来解决,或者是每次都从新从spring容器中通过getBean来获取Bean
		// Let's check for lookup methods here...
		if (!this.lookupMethodsChecked.contains(beanName)) {
			if (AnnotationUtils.isCandidateClass(beanClass, Lookup.class)) {
				try {
					Class<?> targetClass = beanClass;
					do {
						ReflectionUtils.doWithLocalMethods(targetClass, method -> {
							Lookup lookup = method.getAnnotation(Lookup.class);
							if (lookup != null) {
								Assert.state(this.beanFactory != null, "No BeanFactory available");
								LookupOverride override = new LookupOverride(method, lookup.value());
								try {
									RootBeanDefinition mbd = (RootBeanDefinition)this.beanFactory.getMergedBeanDefinition(beanName);
									mbd.getMethodOverrides().addOverride(override);
								}
								catch (NoSuchBeanDefinitionException ex) {
									throw new BeanCreationException(beanName,
											"Cannot apply @Lookup to beans without corresponding bean definition");
								}
							}
						});
						targetClass = targetClass.getSuperclass();
					}
					while (targetClass != null && targetClass != Object.class);

				}
				catch (IllegalStateException ex) {
					throw new BeanCreationException(beanName, "Lookup method resolution failed", ex);
				}
			}
			this.lookupMethodsChecked.add(beanName);
		}

		// 一般只有原型的bean才会创建多次
		// Quick check on the concurrent map first, with minimal locking.
		Constructor<?>[] candidateConstructors = this.candidateConstructorsCache.get(beanClass);
		if (candidateConstructors == null) {
			// Fully synchronized resolution now...
			synchronized (this.candidateConstructorsCache) {
				candidateConstructors = this.candidateConstructorsCache.get(beanClass);
				if (candidateConstructors == null) {
					Constructor<?>[] rawCandidates;
					try {
						// 获取所有构造方法
						rawCandidates = beanClass.getDeclaredConstructors();
					}
					catch (Throwable ex) {
						throw new BeanCreationException(beanName,
								"Resolution of declared constructors on bean Class [" + beanClass.getName() +
								"] from ClassLoader [" + beanClass.getClassLoader() + "] failed", ex);
					}
					// 定义要选举的构造方法集合
					List<Constructor<?>> candidates = new ArrayList<>(rawCandidates.length);

					// 加了@AutoWire()并且是require=true的构造方法
					Constructor<?> requiredConstructor = null;

					// 默认构造发给方法
					Constructor<?> defaultConstructor = null;

					// 返回与 Kotlin 主构造函数相对应的 Java 构造函数, 否则,特别是对于非 Kotlin 类,这只会返回 {@code null}。
					Constructor<?> primaryConstructor = BeanUtils.findPrimaryConstructor(beanClass);

					// 记录合成的构造方法数量,理解为可用的构造方法个数吧
					int nonSyntheticConstructors = 0;

					// 遍历所有的构造方法
					for (Constructor<?> candidate : rawCandidates) {
						if (!candidate.isSynthetic()) {
							nonSyntheticConstructors++;
						}
						else if (primaryConstructor != null) {
							continue;
						}

						// 加了@Autowired的构造方法
						MergedAnnotation<?> ann = findAutowiredAnnotation(candidate);
						if (ann == null) {
							Class<?> userClass = ClassUtils.getUserClass(beanClass);
							if (userClass != beanClass) {
								try {
									Constructor<?> superCtor = userClass.getDeclaredConstructor(candidate.getParameterTypes());

									// 在父类中找@Autowired的构造方法
									ann = findAutowiredAnnotation(superCtor);
								}
								catch (NoSuchMethodException ex) {
									// Simply proceed, no equivalent superclass constructor found...
								}
							}
						}
						if (ann != null) {
							// 如果找到加了@Autowired注解的构造方法,再判断required属性

							// 加了@AutoWire()并且是require=true的构造方法
							if (requiredConstructor != null) {
								throw new BeanCreationException(beanName,
										"Invalid autowire-marked constructor: " + candidate +
										". Found constructor with 'required' Autowired annotation already: " +
										requiredConstructor);
							}
							boolean required = determineRequiredStatus(ann);
							if (required) {
								if (!candidates.isEmpty()) {
									throw new BeanCreationException(beanName,
											"Invalid autowire-marked constructors: " + candidates +
											". Found constructor with 'required' Autowired annotation: " +
											candidate);
								}
								requiredConstructor = candidate;
							}
							candidates.add(candidate);
						}
						else if (candidate.getParameterCount() == 0) {
							// 否则如果构造函数参数个数为0,把它赋值给变量defaultConstructor
							defaultConstructor = candidate;
						}
					}

					// 处理上面遍历后的结果
					if (!candidates.isEmpty()) {
						// Add default constructor to list of optional constructors, as fallback.
						if (requiredConstructor == null) {
							// 如果加了@Autowired、并且没有指定required为true、并且存在默认的构造方法
							if (defaultConstructor != null) {
								// 把默认构造方法加到待筛选的集合中
								candidates.add(defaultConstructor);
							}
							else if (candidates.size() == 1 && logger.isInfoEnabled()) {
								logger.info("Inconsistent constructor declaration on bean with name '" + beanName +
										"': single autowire-marked constructor flagged as optional - " +
										"this constructor is effectively required since there is no " +
										"default constructor to fall back to: " + candidates.get(0));
							}
						}
						candidateConstructors = candidates.toArray(new Constructor<?>[0]);
					}
					// 如果只有一个构造方法,并且构造数的参数大于0
					else if (rawCandidates.length == 1 && rawCandidates[0].getParameterCount() > 0) {
						candidateConstructors = new Constructor<?>[] {rawCandidates[0]};
					}
					// primaryConstructor 做java开发一般都是null
					else if (nonSyntheticConstructors == 2 && primaryConstructor != null &&
							defaultConstructor != null && !primaryConstructor.equals(defaultConstructor)) {
						candidateConstructors = new Constructor<?>[] {primaryConstructor, defaultConstructor};
					}
					// primaryConstructor 做java开发一般都是null
					else if (nonSyntheticConstructors == 1 && primaryConstructor != null) {
						candidateConstructors = new Constructor<?>[] {primaryConstructor};
					}
					else {
						candidateConstructors = new Constructor<?>[0];
					}
					// 把推断的构造方法数组放到缓存map中
					this.candidateConstructorsCache.put(beanClass, candidateConstructors);
				}
			}
		}
		return (candidateConstructors.length > 0 ? candidateConstructors : null);

推断构造方法第一步,先找出可用的构造方法,步骤如下:

1、先找出所有的构造方法。

2、遍历所有构造方法,找出加了@Autowire的构造方法,如果没找到就在父类中找,父类中还找不到,但是存在一个构造方法的参数的个数为0,就作为默认的构造方法;如果找到了加了@Autowire的构造方法,并且require都为true则直接报错。

3、再次过滤上面筛选过的构造方法,如果有默认构造方法就加入候选者的集合;如果上面筛选过后没有合适的构造方法,但是又只有参数个数大于0的构造方法,就把他加入到候选者的列表中。

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#autowireConstructor

protected BeanWrapper autowireConstructor(
			String beanName, RootBeanDefinition mbd, @Nullable Constructor<?>[] ctors, @Nullable Object[] explicitArgs) {
		// 带有参数情况的实例化
		return new ConstructorResolver(this).autowireConstructor(beanName, mbd, ctors, explicitArgs);
	}

org.springframework.beans.factory.support.ConstructorResolver#autowireConstructor

public BeanWrapper autowireConstructor(String beanName, RootBeanDefinition mbd,
			@Nullable Constructor<?>[] chosenCtors, @Nullable Object[] explicitArgs) {

		//实例化BeanWrapper,是包装bean的容器
		BeanWrapperImpl bw = new BeanWrapperImpl();
		this.beanFactory.initBeanWrapper(bw);

		Constructor<?> constructorToUse = null;
		ArgumentsHolder argsHolderToUse = null;
		Object[] argsToUse = null;

		// 1、首先判断是否通过getBean方法指定了构造方法参数值
		// 如果getBean中传入的参数不为空,那么就使用传入的参数
		if (explicitArgs != null) {
			argsToUse = explicitArgs;
		}
		// 否则就需要解析配置文件中的参数
		else {
			Object[] argsToResolve = null;
			// 先尝试从缓存中获取
			synchronized (mbd.constructorArgumentLock) {
				// 缓存中的构造器
				constructorToUse = (Constructor<?>) mbd.resolvedConstructorOrFactoryMethod;

				// 2、针对当前BeanDefinition是否缓存了构造方法和构造方法参数值
				if (constructorToUse != null && mbd.constructorArgumentsResolved) {
					// 在缓存中找到了构造器,就继续从缓存中寻找缓存的构造器参数
					// Found a cached constructor...
					argsToUse = mbd.resolvedConstructorArguments;
					if (argsToUse == null) {
						// 没有缓存的参数,就需要获取配置文件中配置的参数
						argsToResolve = mbd.preparedConstructorArguments;
					}
				}
			}
			// 如果缓存中没有缓存的参数的话,即argsToResolve不为空,就需要解析配置的参数
			if (argsToResolve != null) {
				// 解析参数类型,比如将配置的String类型转换成int、boolean等类型
				argsToUse = resolvePreparedArguments(beanName, mbd, bw, constructorToUse, argsToResolve, true);
			}
		}

		// 3、如果两者任意一个为空,则继续进行下面的步骤
		// 如果没有缓存,就需要从构造函数开始解析
		if (constructorToUse == null || argsToUse == null) {

			// 如果传入的构造器数组不为空,就使用传入的构造器参数,否则通过反射获取class中定义的构造器
			// Take specified constructors, if any.
			Constructor<?>[] candidates = chosenCtors;

			// 3.1 如果没有传入构造方法,那么则获取当前BeanDefinition对应的BeanClass中所有的构造方法作为候选者
			if (candidates == null) {
				Class<?> beanClass = mbd.getBeanClass();
				try {
					// 使用public的构造器或者所有构造器
					candidates = (mbd.isNonPublicAccessAllowed() ?
							beanClass.getDeclaredConstructors() : beanClass.getConstructors());
				}
				catch (Throwable ex) {
					throw new BeanCreationException(mbd.getResourceDescription(), beanName,
							"Resolution of declared constructors on bean Class [" + beanClass.getName() +
							"] from ClassLoader [" + beanClass.getClassLoader() + "] failed", ex);
				}
			}

			// 3.2 判断候选者构造方法是不是只有一个,并且没有指定构造方法参数
			if (candidates.length == 1 && explicitArgs == null && !mbd.hasConstructorArgumentValues()) {
				Constructor<?> uniqueCandidate = candidates[0];
				if (uniqueCandidate.getParameterCount() == 0) {
					synchronized (mbd.constructorArgumentLock) {
						mbd.resolvedConstructorOrFactoryMethod = uniqueCandidate;
						mbd.constructorArgumentsResolved = true;
						mbd.resolvedConstructorArguments = EMPTY_ARGS;
					}
					// 初始化并设置构造器参数
					bw.setBeanInstance(instantiate(beanName, mbd, uniqueCandidate, EMPTY_ARGS));
					return bw;
				}
			}

			// 是否需要解析构造器,在配置文件中指定注入方式为构造器注入
			// Need to resolve the constructor.
			boolean autowiring = (chosenCtors != null ||
					mbd.getResolvedAutowireMode() == AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR);

			// 存放解析后的构造方法参数值
			ConstructorArgumentValues resolvedValues = null;

			int minNrOfArgs;
			if (explicitArgs != null) {
				// getBean方法传入的参数
				minNrOfArgs = explicitArgs.length;
			}
			else {
				// 配置文件中的配置的参数
				ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
				// 用于承载解析后的构造函数参数的值
				resolvedValues = new ConstructorArgumentValues();
				// 解析配置文件中的参数,并且返回参数个数
				minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
			}

			// 3.3 对候选者构造函数排序,public构造函数优先、参数数量降序排序
			AutowireUtils.sortConstructors(candidates);

			// 计算构造方法参数个数最少个数
			// 意思是如果指定了构造方法参数个数,所以当前BeanDefinition对应的BeanClass中所有构造方法参数个数至少满足手动指定的参数值个数
			int minTypeDiffWeight = Integer.MAX_VALUE;

			Set<Constructor<?>> ambiguousConstructors = null;
			LinkedList<UnsatisfiedDependencyException> causes = null;

			// 3.4 遍历所有的构造方法
			for (Constructor<?> candidate : candidates) {
				int parameterCount = candidate.getParameterCount();

				if (constructorToUse != null && argsToUse != null && argsToUse.length > parameterCount) {
					// Already found greedy constructor that can be satisfied ->
					// do not look any further, there are only less greedy constructors left.
					break;
				}

				// 如果候选者参数个数 < minNrOfArgs,则不匹配,继续下一个
				if (parameterCount < minNrOfArgs) {
					continue;
				}

				// 封装解析到的参数信息
				ArgumentsHolder argsHolder;

				Class<?>[] paramTypes = candidate.getParameterTypes();

				// 解析配置文件得到的构造方法参数值
				if (resolvedValues != null) {
					try {
						// 3.5 判断通过getBean方法指定构造方法参数
						String[] paramNames = ConstructorPropertiesChecker.evaluate(candidate, parameterCount);
						if (paramNames == null) {
							ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
							if (pnd != null) {
								paramNames = pnd.getParameterNames(candidate);
							}
						}
						// 参数个数匹配的情况下把所有参数封装为一个ArgumentsHolder对象,不匹配就直接报错了
						argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw, paramTypes, paramNames,
								getUserDeclaredConstructor(candidate), autowiring, candidates.length == 1);
					}
					catch (UnsatisfiedDependencyException ex) {
						if (logger.isTraceEnabled()) {
							logger.trace("Ignoring constructor [" + candidate + "] of bean '" + beanName + "': " + ex);
						}
						// Swallow and try next constructor.
						if (causes == null) {
							causes = new LinkedList<>();
						}
						causes.add(ex);
						continue;
					}
				}
				else {
					// 处理参数由getBean方法传入的情况
					// Explicit arguments given -> arguments length must match exactly.
					if (parameterCount != explicitArgs.length) {
						continue;
					}
					argsHolder = new ArgumentsHolder(explicitArgs);
				}

				// 3.7 计算得到的构造方法参数值和参数的匹配程度
				// 因为不同构造函数的参数个数相同,而且参数类型为父子关系,所以需要找出类型最符合的一个构造函数
				// Spring用一种权重的形式来表示类型差异程度,差异权重越小越优先
				// 如果是以宽松的方式解析,默认为true,所以执行getTypeDifferenceWeight
				int typeDiffWeight = (mbd.isLenientConstructorResolution() ?
						argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes));

				// 当前构造函数最为匹配的话,清空先前ambiguousConstructors列表
				// Choose this constructor if it represents the closest match.
				if (typeDiffWeight < minTypeDiffWeight) {
					constructorToUse = candidate;
					argsHolderToUse = argsHolder;
					argsToUse = argsHolder.arguments;
					minTypeDiffWeight = typeDiffWeight;
					ambiguousConstructors = null;
				}
				// 存在相同权重的构造器,将构造器添加到一个ambiguousConstructors列表变量中
				// 注意,这时候constructorToUse 指向的仍是第一个匹配的构造函数
				else if (constructorToUse != null && typeDiffWeight == minTypeDiffWeight) {
					if (ambiguousConstructors == null) {
						ambiguousConstructors = new LinkedHashSet<>();
						ambiguousConstructors.add(constructorToUse);
					}
					ambiguousConstructors.add(candidate);
				}
			}

			/*******************************************************************************************************/

			if (constructorToUse == null) {
				// 如果没有匹配的构造函数,抛出异常。略
				if (causes != null) {
					UnsatisfiedDependencyException ex = causes.removeLast();
					for (Exception cause : causes) {
						this.beanFactory.onSuppressedException(cause);
					}
					throw ex;
				}
				throw new BeanCreationException(mbd.getResourceDescription(), beanName,
						"Could not resolve matching constructor " +
						"(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities)");
			}
			else if (ambiguousConstructors != null && !mbd.isLenientConstructorResolution()) {
				// 如果存在多个构造函数匹配程度相同,并且BeanDefinition中设置isLenientConstructorResolution为false(默认值为true),
				// 表示构造器创建为严格模式的话,会抛出异常。异常代码略
				throw new BeanCreationException(mbd.getResourceDescription(), beanName,
						"Ambiguous constructor matches found in bean '" + beanName + "' " +
						"(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities): " +
						ambiguousConstructors);
			}

			if (explicitArgs == null && argsHolderToUse != null) {
				argsHolderToUse.storeCache(mbd, constructorToUse);
			}
		}

		Assert.state(argsToUse != null, "Unresolved constructor arguments");

		// 初始化
		bw.setBeanInstance(instantiate(beanName, mbd, constructorToUse, argsToUse));
		return bw;
	}

1、只有一个无参的构造方法,那么直接使用无参的构造方法进行实例化 candidates.length == 1

2、有多个构造方法或者bean需要通过构造方法自动进行注入 ResolvedAutowireMode() == 3

3、根据所指定的构造方法参数值,确定所需要的最少的构造方法参数值的个数 minNrOfArgs

4、对所有的构造方法进行排序,参数个数多的在前面 AutowireUtils.sortConstructors

5、遍历所有的构造方法

6、如果当前构造方法参数个数小于minNrOfArgs则不匹配,继续判断下一个构造方法

7、如果是调用getBean方法指定的参数就直接利用这些值,如果不是就根据构造方法参数类型找值(先byType再byName),匹配的话则封装成一个ArgumentsHolder对象

8、这里可能会匹配到多个构造方法,然后就需要那值和构造方法匹配程度计算一个权重,值越小优先级越高(因为如果是父子类的话子类匹配成功更高)

9、计算权重分为宽松型(默认)和严格型,严格型的情况下如果有多个匹配就报错

到此这篇关于Spring源码解析之推断构造方法的文章就介绍到这了,更多相关Spring推断构造方法内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

时间: 2021-06-10

Java构造器(构造方法)与方法区别说明

构造器,又称为构造方法.构造器用于构造该类的实例,也就是对象. 格式如下:[修饰符] 类名 (形参列表){//n条语句} 构造方法是一种特殊的方法,与一般的方法区别: 1.构造方法的名字必须与定义他的类名完全相同,没有返回类型,甚至连void也没有. 2.构造方法的调用是在创建一个对象时使用new操作进行的.构造方法的作用是初始化对象. 3.不能被static.final.synchronized.abstract和native修饰.构造方法不能被子类继承. 构造方法可以被重载.没有参数的构造方

Java中构造方法set/get和toString的使用详解

一.构造函数 构造函数的最大作用就是创建对象时完成初始化,当我们在new一个对象并传入参数的时候,会自动调用构造函数并完成参数的初始化.如下: public class Test01 { private String name; //有参构造函数 public Test01(String name) { this.name = name; } public static void main(String[] args) { Test01 t=new Test01("Wade"); Sy

Java构造方法实例详解(动力节点java学院整理)

构造函数是一种特殊的函数.其主要功能是用来在创建对象时初始化对象, 即为v对象成员变量赋初始值,总与new运算符一起使用在创建对象的语句中.构造函数与类名相同,可重载多个不同的构造函数.在JAVA语言中,构造函数与C++语言中的构造函数相同,JAVA语言中普遍称之为构造方法. 使用构造器时需要记住: 1.构造器必须与类同名(如果一个源文件中有多个类,那么构造器必须与公共类同名) 2.每个类可以有一个以上的构造器 3.构造器可以有0个.1个或1个以上的参数 4.构造器没有返回值 5.构造器总是伴随

Java8方法引用及构造方法引用原理实例解析

如果不熟悉Java8新特性的小伙伴,初次看到函数式接口写出的代码可能会是一种懵逼的状态,我是谁,我在哪,我可能学了假的Java,(・∀・(・∀・(・∀・*),但是语言都是在进步的,就好比面向对象的语言Java也可以写出优雅的函数式调用,学习的过程并不复杂,当你学会了Java8中函数式编程的新特性,你一定会对他爱不释手的.下面介绍一下基于Lambda表达式简写的两种引用.避免再次看到这种代码时的尴尬

java中静态代码块与构造方法的执行顺序判断

前言 静态代码优先于非静态的代码,是因为被static修饰的成员都是类成员,会随着JVM加载类的时候加载而执行,而没有被static修饰的成员也被称为实例成员,需要创建对象才会随之加载到堆内存.所以静态的会优先非静态的. 执行构造器(构造方法)的时候,在执行方法体之前存在隐式三步: 1,super语句,可能出现以下三种情况: 1)构造方法体的第一行是this语句,则不会执行隐式三步, 2)构造方法体的第一行是super语句,则调用相应的父类的构造方法, 3)构造方法体的第一行既不是this语句也

Java中自动生成构造方法详解

Java中自动生成构造方法详解 每个类在没有声明构造方法的前提下,会自动生成一个不带参数的构造方法,如果类一但声明有构造方法,就不会产生了.证明如下: 例1: class person { person(){System.out.println("父类-person");} person(int z){} } class student extends person { // student(int x ,int y){super(8);} } class Rt { public st

Java中的Random()函数及两种构造方法

Java中存在着两种Random函数: java.lang.Math.Random; 调用这个Math.Random()函数能够返回带正号的double值,该值大于等于0.0且小于1.0,即取值范围是[0.0,1.0)的左闭右开区间,返回值是一个伪随机选择的数,在该范围内(近似)均匀分布. java.util.Random 下面Random()的两种构造方法: Random():创建一个新的随机数生成器. Random(long seed):使用单个 long 种子创建一个新的随机数生成器. 我

Java中的构造方法this、super的用法详解

1.构造方法 定义:与类同名没有返回值的方法称为构造方法: public class test1 { private String name; private int age; public test1(){ } } 上面的test1()是默认构造方法,即使没有定义java虚拟机在运行的时候也会自动生成, 当然如果定义了重载的构造方法便不会自动生成: 构造方法的作用有两点1.通过构造方法建立一个对象:2.通过构造方法可以快速的赋初值: public class Main { public sta

Java中volatile关键字的作用与用法详解

volatile这个关键字可能很多朋友都听说过,或许也都用过.在Java 5之前,它是一个备受争议的关键字,因为在程序中使用它往往会导致出人意料的结果.在Java 5之后,volatile关键字才得以重获生机. volatile 关键字作用是,使系统中所有线程对该关键字修饰的变量共享可见,可以禁止线程的工作内存对volatile修饰的变量进行缓存. volatile 2个使用场景: 1.可见性:Java提供了volatile关键字来保证可见性. 当一个共享变量被volatile修饰时,它会保证修

Java 中组合模型之对象结构模式的详解

Java 中组合模型之对象结构模式的详解 一.意图 将对象组合成树形结构以表示"部分-整体"的层次结构.Composite使得用户对单个对象和组合对象的使用具有一致性. 二.适用性 你想表示对象的部分-整体层次结构 你希望用户忽略组合对象与单个对象的不同,用户将统一使用组合结构中的所有对象. 三.结构 四.代码 public abstract class Component { protected String name; //节点名 public Component(String n

基于java Files类和Paths类的用法(详解)

Java7中文件IO发生了很大的变化,专门引入了很多新的类: import java.nio.file.DirectoryStream; import java.nio.file.FileSystem; import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.attribute.

JS中正则表达式全局匹配模式 /g用法详解

本文章来详细介绍js中正则表达式的全局匹配模式 /g用法,代码如下: var str = "123#abc"; var re = /abc/ig; console.log(re.test(str)); //输出ture console.log(re.test(str)); //输出false console.log(re.test(str)); //输出ture console.log(re.test(str)); //输出false 在创建正则表达式对象时如果使用了"g&q

java 中Excel转shape file的实例详解

java  中Excel转shape file的实例详解 概述: 本文讲述如何结合geotools和POI实现Excel到shp的转换,再结合前文shp到geojson数据的转换,即可实现用户上传excel数据并在web端的展示功能. 截图: 原始Excel文件 运行耗时 运行结果 代码: package com.lzugis.geotools; import com.lzugis.CommonMethod; import com.vividsolutions.jts.geom.Coordina

Python 中 Virtualenv 和 pip 的简单用法详解

本文介绍了Python 中 Virtualenv 和 pip 的简单用法详解,分享给大家,具体如下: 0X00 安装环境 我们在 Python 开发和学习过程中需要用到各种库,然后在各个不同的项目和作品里可能用的版本还不一样,正因为有这种问题的存在才催生了virtualenv的诞生.virtualenv 可以在电脑上创建一个虚拟环境,可以针对每一个项目创建一个虚拟环境,这样就不用担心各个不同的项目用不同版本的库的时候出现的冲突了. 下面的内容只适用于 Linux/OSX,未经 Windows 环

基于java中的PO VO DAO BO POJO(详解)

一.PO:persistant object 持久对象,可以看成是与数据库中的表相映射的ava对象. 最简单的PO就是对应数据库中某个表中的一条记录,多个记录可以用PO的集合PO中应该不包含任何对数据库的操作. 二.VO:value object值对象.通常用于业务层之间的数据传递,和PO一样也是仅仅包含数据而已.但应是抽象出的业务对象可以和表对应也可以不这根据业务的需要 三.DAO:data access object 数据访问对象,此对象用于访问数据库.通常和PO结合使用,DAO中包含了各种

JAVA 中解密RSA算法JS加密实例详解

JAVA 中解密RSA算法JS加密实例详解 有这样一个需求,前端登录的用户名密码,密码必需加密,但不可使用MD5,因为后台要检测密码的复杂度,那么在保证安全的前提下将密码传到后台呢,答案就是使用RSA非对称加密算法解决 . java代码 需要依赖 commons-codec 包 RSACoder.Java import org.apache.commons.codec.binary.Base64; import javax.crypto.Cipher; import java.security.

有关C++中随机函数rand() 和srand() 的用法详解

一.rand() 函数名:   rand 功   能:   随机数发生器 用   法:   int rand(void); 所在头文件: stdlib.h 函数说明 : rand()的内部实现是用线性同余法做的,它不是真的随机数,因其周期特别长,故在一定 的范围里可看成是随机的. rand()返回一随机数值的范围在0至RAND_MAX 间.RAND_MAX的范围最少是在32767之间(int).用 unsigned int 双字节是65535,四字节是4294967295的整数范围.0~RAND

Java中对List集合的常用操作详解

目录: 1.list中添加,获取,删除元素: 2.list中是否包含某个元素: 3.list中根据索引将元素数值改变(替换): 4.list中查看(判断)元素的索引: 5.根据元素索引位置进行的判断: 6.利用list中索引位置重新生成一个新的list(截取集合): 7.对比两个list中的所有元素: 8.判断list是否为空: 9.返回Iterator集合对象: 10.将集合转换为字符串: 11.将集合转换为数组: 12.集合类型转换: 备注:内容中代码具有关联性. 1.list中添加,获取,