从源码层面带你实现一个自动注入注解
首先,需要了解到的是。SpringBean的生命周期在生命周期中。注入bean属性的位置是在以下代码:populateBean位置中
那么我们在项目中使用注解产生一个bean的时候必定会经过以下代码进行一个bean的创建流程
/**省略代码**///开始初始化bean实例对象ObjectexposedObject=bean;try{ //<5>对bean进行填充,将各个属性值注入,其中,递进式指标源码可能存在依赖于其他bean的属性populateBean(beanName,mbd,instanceWrapper);//<6>调用初始化方法exposedObject=initializeBean(beanName,exposedObject,mbd);}catch(Throwableex){ if(exinstanceofBeanCreationException&&beanName.equals(((BeanCreationException)ex).getBeanName())){ throw(BeanCreationException)ex;}else{ thrownewBeanCreationException(mbd.getResourceDescription(),beanName,"Initializationofbeanfailed",ex);}}/**省略代码**/在生命周期中populateBean进行填充bean数据。把其他依赖引入进来
BeanPostProcessor是一个bean创建时候的一个钩子。
以下代码是循环调用实现了BeanPostProcessor子类InstantiationAwareBeanPostProcessor#postProcessProperties方法
Spring在以下代码中有自动注入的拓展点。关键就是实现InstantiationAwareBeanPostProcessor#postProcessProperties
/**省略代码**/for(BeanPostProcessorbp:getBeanPostProcessors()){ if(bpinstanceofInstantiationAwareBeanPostProcessor){ InstantiationAwareBeanPostProcessoribp=(InstantiationAwareBeanPostProcessor)bp;//对所有需要依赖检查的属性进行后处理PropertyValuespvsToUse=ibp.postProcessProperties(pvs,bw.getWrappedInstance(),beanName);if(pvsToUse==null){ //从bw对象中提取PropertyDescriptor结果集//PropertyDescriptor:可以通过一对存取方法提取一个属性if(filteredPds==null){ filteredPds=filterPropertyDescriptorsForDependencyCheck(bw,mbd.allowCaching);}pvsToUse=ibp.postProcessPropertyValues(pvs,filteredPds,bw.getWrappedInstance(),beanName);if(pvsToUse==null){ return;}}pvs=pvsToUse;}}/**省略代码**/我们展开来讲一下@Autowired的实现是怎么样的吧:
实现类为AutowiredAnnotationBeanPostProcessor.java
从上面可以得知,填充bean的时候。时调用了方法ibp.postProcessPropertyValues()
那么AutowiredAnnotationBeanPostProcessor#postProcessPropertyValues()则会被调用
调用findAutowiringMetadata获取class以及父类带有@Autowired或者@Value的属性或者方法:
/**省略代码**/publicPropertyValuespostProcessProperties(PropertyValuespvs,Objectbean,StringbeanName){ //获取所有可以注入的元数据InjectionMetadatametadata=findAutowiringMetadata(beanName,bean.getClass(),pvs);try{ //注入数据metadata.inject(bean,beanName,pvs);}catch(BeanCreationExceptionex){ throwex;}catch(Throwableex){ thrownewBeanCreationException(beanName,"Injectionofautowireddependenciesfailed",ex);}returnpvs;}privateInjectionMetadatafindAutowiringMetadata(StringbeanName,Class<?>clazz,@NullablePropertyValuespvs){ //缓存名字获取StringcacheKey=(StringUtils.hasLength(beanName)?beanName:clazz.getName());InjectionMetadatametadata=this.injectionMetadataCache.get(cacheKey);//获取是否已经读取过这个class类的InjectionMetadata有的话直接从缓存中获取出去if(InjectionMetadata.needsRefresh(metadata,clazz)){ synchronized(this.injectionMetadataCache){ //双重检查metadata=this.injectionMetadataCache.get(cacheKey);if(InjectionMetadata.needsRefresh(metadata,clazz)){ if(metadata!=null){ metadata.clear(pvs);}//构建自动注入的元数据metadata=buildAutowiringMetadata(clazz);this.injectionMetadataCache.put(cacheKey,metadata);}}}returnmetadata;}privateInjectionMetadatabuildAutowiringMetadata(finalClass<?>clazz){ if(!AnnotationUtils.isCandidateClass(clazz,this.autowiredAnnotationTypes)){ returnInjectionMetadata.EMPTY;}List<InjectionMetadata.InjectedElement>elements=newArrayList<>();Class<?>targetClass=clazz;do{ finalList<InjectionMetadata.InjectedElement>currElements=newArrayList<>();//循环targetClass的所有field并执FieldCallback逻辑(函数式编程接口,传入的是一个执行函数)ReflectionUtils.doWithLocalFields(targetClass,field->{ //获得字段上面的Annotation注解MergedAnnotation<?>ann=findAutowiredAnnotation(field);if(ann!=null){ //判断是否为静态属性如果是,则不进行注入if(Modifier.isStatic(field.getModifiers())){ if(logger.isInfoEnabled()){ logger.info("Autowiredannotationisnotsupportedonstaticfields:"+field);}return;}//注解是否为必须依赖项booleanrequired=determineRequiredStatus(ann);currElements.add(newAutowiredFieldElement(field,required));}});//循环targetClass的所有Method并执MethodCallback逻辑(函数式编程接口,传入的是一个执行函数)ReflectionUtils.doWithLocalMethods(targetClass,method->{ MethodbridgedMethod=BridgeMethodResolver.findBridgedMethod(method);if(!BridgeMethodResolver.isVisibilityBridgeMethodPair(method,bridgedMethod)){ return;}MergedAnnotation<?>ann=findAutowiredAnnotation(bridgedMethod);if(ann!=null&&method.equals(ClassUtils.getMostSpecificMethod(method,clazz))){ //判断是否为静态方法如果是,则不进行注入if(Modifier.isStatic(method.getModifiers())){ if(logger.isInfoEnabled()){ logger.info("Autowiredannotationisnotsupportedonstaticmethods:"+method);}return;}//判断静态方法参数是否为0if(method.getParameterCount()==0){ if(logger.isInfoEnabled()){ logger.info("Autowiredannotationshouldonlybeusedonmethodswithparameters:"+method);}}booleanrequired=determineRequiredStatus(ann);PropertyDescriptorpd=BeanUtils.findPropertyForMethod(bridgedMethod,clazz);currElements.add(newAutowiredMethodElement(method,required,pd));}});//数据加到数组最前方父类的的注解都放在靠前的位置elements.addAll(0,currElements);//如果有父类则设置targetClass为父类。如此循环targetClass=targetClass.getSuperclass();}while(targetClass!=null&&targetClass!=Object.class);returnInjectionMetadata.forElements(elements,clazz);}/**省略代码**/真正注入数据的是metadata.inject(bean,beanName,pvs);
调用的是InjectionMetadata#inject方法
publicvoidinject(Objecttarget,@NullableStringbeanName,@NullablePropertyValuespvs)throwsThrowable{ Collection<InjectedElement>checkedElements=this.checkedElements;//带有注解的方法或者属性列表Collection<InjectedElement>elementsToIterate=(checkedElements!=null?checkedElements:this.injectedElements);if(!elementsToIterate.isEmpty()){ for(InjectedElementelement:elementsToIterate){ element.inject(target,beanName,pvs);}}}循环调用之前加入的带有注解的方法或者属性构建的对象AutowiredFieldElement#inject,AutowiredMethodElement#inject
/***属性上有注解构建的处理对象*/privateclassAutowiredFieldElementextendsInjectionMetadata.InjectedElement{ privatefinalbooleanrequired;privatevolatilebooleancached;@NullableprivatevolatileObjectcachedFieldValue;publicAutowiredFieldElement(Fieldfield,booleanrequired){ super(field,null);this.required=required;}@Overrideprotectedvoidinject(Objectbean,@NullableStringbeanName,@NullablePropertyValuespvs)throwsThrowable{ //获取属性名Fieldfield=(Field)this.member;Objectvalue;//Bean不是单例的话,会重复进入注入的这个操作,if(this.cached){ try{ value=resolvedCachedArgument(beanName,this.cachedFieldValue);}catch(NoSuchBeanDefinitionExceptionex){ //Unexpectedremovaloftargetbeanforcachedargument->re-resolvevalue=resolveFieldValue(field,bean,beanName);}}else{ //首次创建的时候进入该方法value=resolveFieldValue(field,bean,beanName);}if(value!=null){ //属性如果不为public的话,则设置为可访问ReflectionUtils.makeAccessible(field);field.set(bean,value);}}@NullableprivateObjectresolveFieldValue(Fieldfield,Objectbean,@NullableStringbeanName){ //构建DependencyDescriptor对象DependencyDescriptordesc=newDependencyDescriptor(field,this.required);desc.setContainingClass(bean.getClass());//注入bean的数量。有可能字段上是一个ListSet<String>autowiredBeanNames=newLinkedHashSet<>(1);Assert.state(beanFactory!=null,"NoBeanFactoryavailable");//获得beanFactory类型转换类TypeConvertertypeConverter=beanFactory.getTypeConverter();Objectvalue;try{ //查找依赖关系value=beanFactory.resolveDependency(desc,beanName,autowiredBeanNames,typeConverter);}catch(BeansExceptionex){ thrownewUnsatisfiedDependencyException(null,beanName,newInjectionPoint(field),ex);}synchronized(this){ if(!this.cached){ ObjectcachedFieldValue=null;if(value!=null||this.required){ cachedFieldValue=desc;//填入依赖关系registerDependentBeans(beanName,autowiredBeanNames);//判断如果注入依赖是只有一个if(autowiredBeanNames.size()==1){ StringautowiredBeanName=autowiredBeanNames.iterator().next();if(beanFactory.containsBean(autowiredBeanName)&&beanFactory.isTypeMatch(autowiredBeanName,field.getType())){ cachedFieldValue=newShortcutDependencyDescriptor(desc,autowiredBeanName,field.getType());}}}this.cachedFieldValue=cachedFieldValue;this.cached=true;}}returnvalue;}}/***方法上有注解构建的处理对象*/privateclassAutowiredMethodElementextendsInjectionMetadata.InjectedElement{ privatefinalbooleanrequired;privatevolatilebooleancached;@NullableprivatevolatileObject[]cachedMethodArguments;publicAutowiredMethodElement(Methodmethod,booleanrequired,@NullablePropertyDescriptorpd){ super(method,pd);this.required=required;}@Overrideprotectedvoidinject(Objectbean,@NullableStringbeanName,@NullablePropertyValuespvs)throwsThrowable{ //检查属性是不会在之前就已经注入过了。如果主如果则不进行二次覆盖if(checkPropertySkipping(pvs)){ return;}Methodmethod=(Method)this.member;Object[]arguments;if(this.cached){ try{ arguments=resolveCachedArguments(beanName);}catch(NoSuchBeanDefinitionExceptionex){ //Unexpectedremovaloftargetbeanforcachedargument->re-resolvearguments=resolveMethodArguments(method,bean,beanName);}}else{ //首次创建的时候进入该方法arguments=resolveMethodArguments(method,bean,beanName);}if(arguments!=null){ try{ //属性如果不为public的话,则设置为可访问ReflectionUtils.makeAccessible(method);//调用方法并传入参数method.invoke(bean,arguments);}catch(InvocationTargetExceptionex){ throwex.getTargetException();}}}@NullableprivateObject[]resolveCachedArguments(@NullableStringbeanName){ Object[]cachedMethodArguments=this.cachedMethodArguments;if(cachedMethodArguments==null){ returnnull;}Object[]arguments=newObject[cachedMethodArguments.length];for(inti=0;i<arguments.length;i++){ arguments[i]=resolvedCachedArgument(beanName,cachedMethodArguments[i]);}returnarguments;}@NullableprivateObject[]resolveMethodArguments(Methodmethod,Objectbean,@NullableStringbeanName){ //获取方法上有几个参数intargumentCount=method.getParameterCount();Object[]arguments=newObject[argumentCount];DependencyDescriptor[]descriptors=newDependencyDescriptor[argumentCount];Set<String>autowiredBeans=newLinkedHashSet<>(argumentCount);Assert.state(beanFactory!=null,"NoBeanFactoryavailable");TypeConvertertypeConverter=beanFactory.getTypeConverter();for(inti=0;i<arguments.length;i++){ //方法参数,从方法参数中取出i构造MethodParameter对象MethodParametermethodParam=newMethodParameter(method,i);DependencyDescriptorcurrDesc=newDependencyDescriptor(methodParam,this.required);currDesc.setContainingClass(bean.getClass());descriptors[i]=currDesc;try{ //获取方法中i参数的内容Objectarg=beanFactory.resolveDependency(currDesc,beanName,autowiredBeans,typeConverter);if(arg==null&cè¯è¨ç¨åºä»£ç å¤§å ¨(cè¯è¨ç¨åºç¼ç¨ä»£ç å¤§å ¨)
cè¯è¨ç¨åºä»£ç
Cè¯è¨æºä»£ç ï¼å°±æ¯ä¾æ®Cè¯è¨è§åæååºçç¨åºä»£ç ï¼å¸¸è§çåå¨æ件æ©å±å为.cæ件å.hæ件ï¼åå«å¯¹åºCæºæ件(sourcefile)åC头æ件(headerfile)ã
Cè¯è¨æ¯ä¸é¨ç¼ç¨è¯è¨ï¼ç®åç¹è¯´ï¼å°±æ¯ç±äººç±»ä¹¦åæç §ä¸å®è§è书åçå符ï¼éè¿ä¸å®æ段ï¼ç¼è¯é¾æ¥ï¼è½¬æ¢åï¼å¯ä»¥è®©çµèæè å ¶å®çµåè¯çï¼è¯»æï¼ï¼å¹¶æç §å ¶è¦æ±å·¥ä½çè¯è¨ãå¨ææçç¼ç¨è¯è¨ä¸ï¼Cè¯è¨æ¯ç¸å¯¹å¤èèåå§çï¼åæ¶ä¹æ¯å¨åç±»è¯è¨ä¸æ´æ¥è¿ç¡¬ä»¶ï¼æ为é«æçç¼ç¨è¯è¨ã
ç¸å ³å 容ï¼
Cè¯è¨æ¯ä¸é¨é¢åè¿ç¨ç计ç®æºç¼ç¨è¯è¨ï¼ä¸C++ãC#ãJavaçé¢å对象ç¼ç¨è¯è¨ææä¸åãCè¯è¨ç设计ç®æ æ¯æä¾ä¸ç§è½ä»¥ç®æçæ¹å¼ç¼è¯ãå¤çä½çº§åå¨å¨ãä» äº§çå°éçæºå¨ç 以åä¸éè¦ä»»ä½è¿è¡ç¯å¢æ¯æ便è½è¿è¡çç¼ç¨è¯è¨ã
Cè¯è¨æè¿°é®é¢æ¯æ±ç¼è¯è¨è¿ éãå·¥ä½éå°ãå¯è¯»æ§å¥½ãæäºè°è¯ãä¿®æ¹å移æ¤ï¼è代ç è´¨éä¸æ±ç¼è¯è¨ç¸å½ãCè¯è¨ä¸è¬åªæ¯æ±ç¼è¯è¨ä»£ç çæçç®æ ç¨åºæçä½%-%ãå æ¤ï¼Cè¯è¨å¯ä»¥ç¼åç³»ç»è½¯ä»¶ã
å½åé¶æ®µï¼å¨ç¼ç¨é¢åä¸ï¼Cè¯è¨çè¿ç¨é常ä¹å¤ï¼å®å ¼é¡¾äºé«çº§è¯è¨åæ±ç¼è¯è¨çä¼ç¹ï¼ç¸è¾äºå ¶å®ç¼ç¨è¯è¨å ·æè¾å¤§ä¼å¿ã计ç®æºç³»ç»è®¾è®¡ä»¥ååºç¨ç¨åºç¼åæ¯Cè¯è¨åºç¨ç两大é¢åãåæ¶ï¼Cè¯è¨çæ®éè¾å¼ºï¼å¨è®¸å¤è®¡ç®æºæä½ç³»ç»ä¸é½è½å¤å¾å°éç¨ï¼ä¸æçæ¾èã
Cè¯è¨æ¥æç»è¿äºæ¼«é¿åå±åå²çå®æ´çç论ä½ç³»ï¼å¨ç¼ç¨è¯è¨ä¸å ·æ举足轻éçå°ä½ã
cè¯è¨è·ªæ±æç®åçæ±åç¨åºä»£ç
ä¸é¢æ¯Cè¯è¨ä¸çä¸ä¸ªæç®åçæ±åç¨åºï¼
Copycode#includestdio.h
intmain()
{
intnum1=1,num2=2,sum;
sum=num1+num2;
printf("两æ°ä¹å为ï¼%d",sum);
return0;
}
å¨è¿ä¸ªç¨åºä¸ï¼æ们å®ä¹äºä¸¤ä¸ªæ´ååénum1ånum2ï¼å¹¶å°å®ä»¬ç¸å å¾å°sumãæåè¾åºäºsumçå¼ã
è¿ä¸ªç¨åºæ¯æç®åçæ±åç¨åºä¹ä¸ï¼åªæ¶åå°ä¸¤ä¸ªæ°åçç¸å æä½ï¼é常æäºç解åæä½ãä½æ¯ï¼éè¦æ³¨æçæ¯ï¼å¨å®é ç¼åå¤æçç¨åºæ¶ï¼è¿éè¦å¦ä¹ æ´å¤çCè¯è¨ç¥è¯åæå·§ã
cè¯è¨å¿ è代ç æåªäºï¼1ã/*è¾åº9*9å£è¯ãå ±9è¡9åï¼iæ§å¶è¡ï¼jæ§å¶åã*/
#include"stdio.h"
main()
{ inti,j,result;
for(i=1;i;i++)
{ for(j=1;j;j++)
{
result=i*j;
printf("%d*%d=%-3d",i,j,result);/*-3d表示左对é½ï¼å 3ä½*/
}
printf("\n");/*æ¯ä¸è¡åæ¢è¡*/
}
}
2ã/*å¤å ¸é®é¢ï¼æä¸å¯¹å åï¼ä»åºçå第3个æèµ·æ¯ä¸ªæé½çä¸å¯¹å åï¼å°å åé¿å°ç¬¬ä¸ä¸ªæåæ¯ä¸ªæåçä¸å¯¹å åï¼åå¦å åé½ä¸æ»ï¼é®æ¯ä¸ªæçå åæ»æ°ä¸ºå¤å°ï¼
å åçè§å¾ä¸ºæ°å1,1,2,3,5,8,,....*/
main()
{
longf1,f2;
inti;
f1=f2=1;
for(i=1;i=;i++)
{ printf("%ld%ld",f1,f2);
if(i%2==0)printf("\n");/*æ§å¶è¾åºï¼æ¯è¡å个*/
f1=f1+f2;/*å两个æå èµ·æ¥èµå¼ç»ç¬¬ä¸ä¸ªæ*/
f2=f1+f2;/*å两个æå èµ·æ¥èµå¼ç»ç¬¬ä¸ä¸ªæ*/
}
}
3ã/*å¤æ-ä¹é´æå¤å°ä¸ªç´ æ°ï¼å¹¶è¾åºææç´ æ°åç´ æ°ç个æ°ã
ç¨åºåæï¼å¤æç´ æ°çæ¹æ³ï¼ç¨ä¸ä¸ªæ°åå«å»é¤2å°sqrt(è¿ä¸ªæ°)ï¼å¦æè½è¢«æ´é¤ï¼
å表ææ¤æ°ä¸æ¯ç´ æ°ï¼åä¹æ¯ç´ æ°ã*/
#include"math.h"
main()
{
intm,i,k,h=0,leap=1;
printf("\n");
for(m=;m=;m++)
{ k=sqrt(m+1);
for(i=2;i=k;i++)
if(m%i==0)
{ leap=0;break;}
if(leap)?/*å 循ç¯ç»æåï¼leapä¾ç¶ä¸º1ï¼åmæ¯ç´ æ°*/
{ printf("%-4d",m);h++;
if(h%==0)
printf("\n");
}
leap=1;
}
printf("\nThetotalis%d",h);
}
4ã/*ä¸ä¸ªæ°å¦ææ°å¥½çäºå®çå åä¹åï¼è¿ä¸ªæ°å°±ç§°ä¸º"å®æ°"ãä¾å¦6=1ï¼2ï¼3.ç¼ç¨
æ¾åºä»¥å çææå®æ°ã*/
main()
{
staticintk[];
inti,j,n,s;
for(j=2;j;j++)
{
n=-1;
s=j;
for(i=1;ij;i++)
{ if((j%i)==0)
{ ?n++;
s=s-i;
k[n]=i;
}
}
if(s==0)
{ printf("%disawanshu:?",j);
for(i=0;in;i++)
printf("%d,",k[i]);
printf("%d\n",k[n]);
}
}
}
5ã/*ä¸é¢ç¨åºçåè½æ¯å°ä¸ä¸ª4Ã4çæ°ç»è¿è¡éæ¶éæ转度åè¾åºï¼è¦æ±åå§æ°ç»çæ°æ®éæºè¾å ¥ï¼æ°æ°ç»ä»¥4è¡4åçæ¹å¼è¾åºï¼
请å¨ç©ºç½å¤å®åç¨åºã*/
main()
{ ?int?a[4][4],b[4][4],i,j;/*aåæ¾åå§æ°ç»æ°æ®ï¼båæ¾æ转åæ°ç»æ°æ®*/
printf("inputnumbers:");
/*è¾å ¥ä¸ç»æ°æ®åæ¾å°æ°ç»aä¸ï¼ç¶åæ转åæ¾å°bæ°ç»ä¸*/
for(i=0;i4;i++)
for(j=0;j4;j++)
{ ?scanf("%d",a[i][j]);
b[3-j][i]=a[i][j];
}
printf("arrayb:\n");
for(i=0;i4;i++)
{ ?for(j=0;j4;j++)
printf("%6d",b[i][j]);
printf("\n");
}
}
6ã/*ç¼ç¨æå°ç´è§æ¨è¾ä¸è§å½¢*/
main()
{ inti,j,a[6][6];
for(i=0;i=5;i++)
{ a[i][i]=1;a[i][0]=1;}
for(i=2;i=5;i++)
for(j=1;j=i-1;j++)
a[i][j]=a[i-1][j]+a[i-1][j-1];
for(i=0;i=5;i++)
{ for(j=0;j=i;j++)
printf("%4d",a[i][j]);
printf("\n");}
}
7ã/*éè¿é®çè¾å ¥3åå¦ç4é¨è¯¾ç¨çæ绩ï¼
åå«æ±æ¯ä¸ªå¦ççå¹³åæ绩åæ¯é¨è¯¾ç¨çå¹³åæ绩ã
è¦æ±æææ绩åæ¾å ¥ä¸ä¸ª4è¡5åçæ°ç»ä¸ï¼è¾å ¥æ¶åä¸äººæ°æ®é´ç¨ç©ºæ ¼,ä¸å人ç¨å车
å ¶ä¸æåä¸ååæåä¸è¡åå«æ¾æ¯ä¸ªå¦ççå¹³åæ绩ãæ¯é¨è¯¾ç¨çå¹³åæ绩åç级æ»å¹³ååã*/
#includestdio.h
#includestdlib.h
main()
{ floata[4][5],sum1,sum2;
inti,j;
for(i=0;i3;i++)
for(j=0;j4;j++)
scanf("%f",a[i][j]);
for(i=0;i3;i++)
{ sum1=0;
for(j=0;j4;j++)
sum1+=a[i][j];
a[i][4]=sum1/4;
}
æ±è¡ç®åCè¯è¨ç¨åºä»£ç ï¼åºç¡ç就好#includestdio.h
#includestdlib.h
#defineNUM
/*runthisprogramusingtheconsolepauseroraddyourowngetch,system("pause")orinputloop*/
//å泡æåºç®æ³
//åºæ¬ææ³ï¼æ¯è¾ç¸é»ç两个æ°ï¼å¦æåè æ¯åè 大ï¼åè¿è¡äº¤æ¢ãæ¯ä¸è½®æåºç»æï¼éåºä¸ä¸ªæªæåºä¸æ大çæ°æ¾å°æ°ç»åé¢ã
voidbubbleSort(int*arr,intn){
inti,j;
for(i=0;in-1;i++)
for(j=0;jn-i-1;j++){
//å¦æåé¢çæ°æ¯åé¢å¤§ï¼è¿è¡äº¤æ¢
if(arr[j]arr[j+1]){
inttemp=arr[j];
arr[j]=arr[j+1];
arr[j+1]=temp;
}
}
}
//æå·®æ¶é´å¤æ度为O(n^2),å¹³åæ¶é´å¤æ度为O(n^2)ã稳å®æ§ï¼ç¨³å®ãè¾ å©ç©ºé´O(1)ã
//å级çå泡æåºæ³ï¼éè¿ä»ä½å°é«éåºæ大çæ°æ¾å°åé¢ï¼åä»é«å°ä½éåºæå°çæ°æ¾å°åé¢ï¼
//å¦æ¤åå¤ï¼ç´å°å·¦è¾¹çåå³è¾¹çéåãå½æ°ç»ä¸æå·²æåºå¥½çæ°æ¶ï¼è¿ç§æåºæ¯ä¼ ç»å泡æåºæ§è½ç¨å¥½ã
//å级çå泡æåºç®æ³
voidbubbleSort_1(int*arr,intn){
//设置æ°ç»å·¦å³è¾¹ç
intleft=0,right=n-1;
//å½å·¦å³è¾¹çæªéåæ¶ï¼è¿è¡æåº
while(left=right){
inti,j;
//ä»å·¦å°å³éåéåºæ大çæ°æ¾å°æ°ç»å³è¾¹
for(i=left;iright;i++){
if(arr[i]arr[i+1]){
inttemp=arr[i];
arr[i]=arr[i+1];
arr[i+1]=temp;
}
}
right--;
//ä»å³å°å·¦éåéåºæå°çæ°æ¾å°æ°ç»å·¦è¾¹
for(j=right;jleft;j--){
if(arr[j+1]arr[j]){
inttemp=arr[j];
arr[j]=arr[j+1];
arr[j+1]=temp;
}
}
left++;
}
}
intmain(intargc,char*argv[]){
intarr[NUM],i,j,temp;
printf("请è¾å ¥ä¸ªæ°ï¼\n");
for(i=0;iNUM;i++){
printf("请è¾å ¥ç¬¬(%d)个æ°ï¼",i+1);
scanf("%d",arr[i]);
}
printf("\nè¾å ¥å¦ä¸æåï¼\n");
for(i=0;iNUM;i++){
printf("%4d",arr[i]);
}/
*for(i=0;iNUM;i++){
for(j=i+1;jNUM;j++){
if(arr[i]arr[j]){
temp=arr[i];
arr[i]=arr[j];
arr[j]=temp;
}
}
}*/
bubbleSort_1(arr,NUM);
/*printf("\nä»å°å°å¤§å¦ä¸æåï¼\n");
for(i=0;iNUM;i++){
printf("%4d",arr[i]);
}*/
printf("\nä»å¤§å°å°å¦ä¸æåï¼\n");
for(i=NUM-1;i=0;i--){
printf("%4d",arr[i]);
}
return0;
}
cè¯è¨ç¼ç¨ä»£ç 两ç§æ¹æ³æåå¨ä¸èµ·ï¼å¯ä»¥ç¬ç«æå¼ã
#includestdio.h
voidfinda1(chara[3][]);
voidfinda2(chara[3][]);
voidshow(char(*p)[]);
intmain()
{
chara[3][]={ { "gehajl"},{ "aa7"},{ "ccabbbabbb"}};printf("åæ°ç»å 容:\n");show(a);printf("\n1ãç¨æ°ç»æéçæ¹æ³ï¼å½æ°finda1ï¼ï¼\n");finda1(a);printf("æ§è¡å:\n");show(a);printf("\n---------------------\n");charb[3][]={ { "gehajl"},{ "aa7"},{ "ccabbbabbb"}};printf("åæ°ç»å 容:\n");show(a);printf("\n2ãç¨æéæ°ç»çæ¹æ³ï¼å½æ°finda2ï¼ï¼\n");finda2(b);printf("æ§è¡å:\n");show(b);return0;}
voidfinda1(chara[3][])
{
inti,j;char(*p)[]=a;for(i=0;i3;i++)for(j=0;j;j++)
if(p[i][j]=='a')printf("åç°ï¼ç¬¬%dè¡ç¬¬%d个å ç´ æ¯âaâï¼å·²æ¿æ¢\n",i+1,j+1),p[i][j]='1';
}
voidfinda2(chara[3][])
{
inti,j;char*p[3]={ a[0][0],a[1][0],a[2][0]};for(i=0;i3;i++)for(j=0;j;j++)
if(p[i][j]=='a')printf("åç°ï¼ç¬¬%dè¡ç¬¬%d个å ç´ æ¯âaâï¼å·²æ¿æ¢\n",i+1,j+1),p[i][j]='1';
}
voidshow(char(*p)[])
{
inti,j;for(i=0;i3;i++,printf("\n"))for(j=0;j;j++)
printf("%c",p[i][j]);}
原始数据类型和引用数据类型(原始类型和引用类型有什么区别)
基本数据类型和引用类型的区别是什么?
一、含义不同:
基本数据类型存放的是一个值,而引用类型存放的是一个(对象)地址。
二、影响不同:
基本数据类型由于在内存中的ios 答题app源码一个地址存放的是这些变量的值,所以调用函数,函数里的形参,就是复制这些变量的值,以后对形参值的变化,不会影响到原来变量的值;
引用数据类型由于在内存中是引用他的一个内存地址而不是具体的值,所以调用函数,函数里的形参,就是复制这些变量的值的地址,当对形参的值进行修改的时候,就等于是对这些变量的值,进行修改,所以会影响到原来变量的值。
引用的规则
(1)引用被创建的同时必须被初始化(指针则可以在任何时候被初始化)。
(2)不能有NULL引用,引用必须与合法的存储单元关联(指针则可以是NULL)。
(3)一旦引用被初始化,就不能改变引用的关系(指针则可以随时改变所指的对象)。
以下示例程序中,k被初始化为i的引用。
语句k=j并不能将k修改成为j的引用,只是把k的值改变成为6。
由于k是i的引用,所以i的值也变成了6。
以上内容参考:百度百科-引用类型
Java基本数据类型都有什么呢?
变量就是用来储存值而保留的内存位置。这就意味着当你创建一个变量时就会在内存中占用一定的空间。
基于变量的数据类型,操作系统会进行内存分配并且决定什么将被储存在保留内存中。因此,openjdk7源码通过给变量分配不同的数据类型,你可以在这些变量中存储整数,小数或者字字母。
Java中有两种有效地数据类型:原始数据类型,引用数据类型。
1.原始数据类型
Java支持8种原始数据类型。原始数据类型是由该语言预先定义的并用关键词命名的。下面让我们深入学习一下这8种数据类型。
字节型
byte
字节型是一种8位有正负的二进制整数
最小值是-(-2^7)
最大值是(2^7-1)
默认值为0
字节型数据类型主要是为了在大型数组内节省空间,主要是替代整数由于字节型比整数小4倍。
例如:bytea=,byteb=-
短整形
short
短整数是一种位有正负的二进制整数
最小值是-(-2^)
最大值是(2^-1)
短整数类型的数据也可以像字节型一样用于节省空间。短整数比整数小两倍
默认值为0
例如:shorts=,shortr=-
整数型
int
整数型是一种位有正负的二进制整数
最小值是-2,,,(-2^)
最大值是2,,,(2^-1)
整数型一般默认被应用于整数值除非担心内存不够用。
默认值为0
例如:inta=,intb=-
长整形
long
长整型是一种位有正负的二进制整数
最小值是-9,,,,,,(-2^)
最大值是9,,,,,,(2^-1)
这种数据类型一般是在需要比整数型范围更大时应用。
默认值为0L
例如:longa=L,intb=-L
浮点型
float
浮点型数据是一种单精度的位IEEE标准下的浮点数据。
浮点型数据主要是为了在大型浮点数字数组中节约内存。
默认值是0.0f。
浮点型数据不能用于如货币这样的精确数据。
例如:floatf1=.5f
双精度型
double
双精度型数据是一种双精度的位IEEE标准下的浮点数据。
这种数据类型主要是默认被用于表示小数的值,一般是默认的选择。
双精度型数据不能用于如货币这样的精确数据。
默认值是0.0d
例如:doubled1=.4
布尔型
boolean
布尔型数据代表一个信息比特。
它只有两个可能的值:真(true)和假(false)
这种数据类型用于真假条件下的简单标记。
默认值是假(false)
例如:booleanone=true
字符型
char
字符型数据是简单的位Unicode标准下的字符。
最小值是:'\u'(或0)。
最大值是:'\uffff'(或,)。
字符型数据可以用来储存任意字母。
例如:charletterA(字符型的开源商城 asp源码字母A)='A'
2.引用数据类型
引用数据类型是由类的编辑器定义的。他们是用于访问对象的。这些变量被定义为不可更改的特定类型。例如:Employee,Puppy等等。
类对象和数组变量就是这种引用数据类型。
任何引用数据类型的默认值都为空。
一个引用数据类型可以被用于任何声明类型和兼容类型的对象。
例如:Animalanimal=newAnimal("giraffe");
Java常量
常量是代表固定值的源代码。他们直接以代码的形式代表而没有任何估计。常量可以被分配给任意的原始变量类型。例如:
bytea=;chara='A';
字节型,整数型,长整型和短整型也可以由十进制,十六进制和八进制计数系统表示。
当用这些技术系统表示直接量时,前缀0是为了标明八进制,前缀0x是为了标明十六进制。例如:
intdecimal=;intoctal=;inthexa=0x;
Java中的字符串型常量的规定和其他大多数语言一样,也是要写在双引号中间。字符串型直接量的例子如下:
"HelloWorld""two\nlines""\"Thisisinquotes\""""
字符和字符串型常量可以包含任意的Unicode字母。例如:
chara='\u';Stringa=""\u"";
Java语言也支持一些特殊的转义序列的字符和字符串直接量。他们是:
转义字符?含义
\n?换行(0)
\r?回车(0x0d)
\f?换页(0x0c)
\b?退格(0x)
\s?空格(0x)
\t?tab
\""?双引号
\'?单引号?
\?反斜杠
\uxxxx?十六进制UNICODE字符(xxxx)
欢迎想学习Java的小伙伴加入Java学习交流群,群号码:?长按复制?我们一起学Java!
java原始数据类型有哪些JAVA数据类型分基本数据类型和引用数据类型。
基本数据类型
Java里面包含8个基本数据类型,分别是:
boolean、byte、char、c 动态菜单 源码short、int、float、douboe、long
byte字节
byte是JAVA中最小的数据类型,它在内存中占8位(8个bit),取值范围从-到
赋值:byteI=
short短整型
short类型在内存中占2个字节,取值范围从-到
赋值:shorti=;
char字符型
char类型在内存中占2个字节。表示一个字符,也可以使用ASCII码范围内的值来给char型的变量赋值。由于字符在内存中的取值不存在负数范围,所有取值范围从0到
赋值:chari=‘a’;或者chari=;
int整型
int型在内存中占4个字节。取值范围从-到
赋值:inti=;
float单精度浮点型
float型在内存中占4个字节。取值范围从-3.4E到3.4E
赋值:floati=1.0f;
long长整型
long型在内存中占8个字节。取值范围从-到
double双精度浮点型
double型在内存中占8个字节。取值范围从-1.7E到1.7E
boolean布尔型
boolean类型只有两个值:true和false。
基本数据类型的相互转换
转型规则
JAVA中所有的数字变量都是有符号(正负)的。
JAVA不允许类型的随意转换。只有数字变量可以进行转换,但是不能随意。
带有小数点的数字变量默认都为double型。定义float型必须进行强制类型转换。
所占字节数小的数字型变量赋值给所占字节数比它大的类型时不用强制类型转换,此时是自动转型。
int型变量赋值给char型变量时,JVM会以int型变量值到ASCII码表中查找出所对应的字符,再赋值给char型变量。反之也是。但是遵循第4条规则。
初始化简单数据类型时要注意赋值的范围,超出则会产生编译错误。
基本数据类型默认初值
类型初始值
booleanfalse
byte0
char0
short0
int0
float0.0
double0.0
long0
基本数据类型默认初值表
引用数据类型
JAVA中,非简单数据类型的类型都是引用数据类型。
基本数据类型和引用类型的区别基本数据类型和引用类型的区别如下:
一、声明变量时内存分配不同
基本类型:在栈中,因为占据空间是固定的,可以将他们存在较小的内存中-栈中,这样便于迅速查询变量的值。
二、不同的内存分配带来不同的访问机制
在javascript中是不允许直接访问保存在堆内存中的对象的,所以在访问一个对象时,首先得到的是这个对象在堆内存中的地址,然后再按照这个地址去获得这个对象中的值,这就是传说中的按引用访问。?而原始类型的值则是可以直接访问到的。
三、参数传递的不同
原始值:只是把变量里的值传递给参数,之后参数和这个变量互不影响。
引用值:对象变量它里面的值是这个对象在堆内存中的内存地址,这一点你要时刻铭记在心!
四、复制变量时的不同
原始值:在将一个保存着原始值的变量复制给另一个变量时,会将原始值的副本赋值给新变量,此后这两个变量是完全独立的,他们只是拥有相同的value而已。
引用值:在将一个保存着对象内存地址的变量复制给另一个变量时,会把这个内存地址赋值给新变量,也就是说这两个变量都指向了堆内存中的同一个对象,他们中任何一个作出的改变都会反映在另一个身上。
在java中,怎么理解原生数据类型和引用数据类型。原生数据类型有哪些,引用数据类型有哪些。你可以这样理解,基本数据类型:int
java简单代码小游戏?
求一个简单又有趣的JAVA小游戏代码
System.out.println(猜数字游戏,请输入一个数0到,输入-1结束游戏:);inti=sc.nextInt();if(i==-1){ break;}count++;if(ir){ System.out.print(你猜小了。
System.out.println(helloworld!);}}基本概念Java是一种可以撰写跨平台应用软件的面向对象的程序设计语言。
--求大神指点如何用java做扫雷小游戏详细...有源代码吗--怎么用Java做一个扫雷程序,要原创。。做好了给加--求高手写一个扫雷的JAVA代码,我愿出的悬赏或者更多。
最不会加注释了,不知道行不行,一共行,要求全部完成。
用JAVA编一个小游戏或者其他程序1、存盘退出游戏,可以记录当时的敌人的坦克坐标,并可以恢复java如何操作声音文件/②JAVA课程设计,求个能用eclipse实现小游戏或小程序的源代码。
2、--求一个java扫雷游戏的程序源代码,尽量多点注释,要确实可用...--求大神指点如何用java做扫雷小游戏详细...有源代码吗--怎么用Java做一个扫雷程序,要原创。。
3、首先学习myEclipse软件。如果小游戏的话,你需要用到Swing编程,多看看这方面的知识。如果要数据处理的话,你还得学习MySQL数据库。连接起来即可。如果在网页上写个俄罗斯啥的,你就更需要学习,jsp页面编程等。
4、//您好!以下是/question/html回答的程序。//本人试了一下。这个程序非常值得学习。//只要把该对话框内所有的字复制粘贴到Eclipse或者JGrasp就可以运行了。
5、编写好的java程序(*.java),首先要用javac.exe编译成为字节码文件(*.class),然后使用java.exe来执行。建议你下载一个eclipse,用集成开发环境,这个比较方便。
求一个简单的JAVA游戏代码,行左右,谢谢!
下面是一个可能的Java源代码,它包含了一个接口(Shape)和五个类(Circle,Rectangle,Triangle,Square和Main)。它的功能是计算不同形状的面积和周长。
简单第一啊,只要涉及JAVA前面一些章节就行了,谢谢啦。...简单第一啊,只要涉及JAVA前面一些章节就行了,谢谢啦。
最不会加注释了,不知道行不行,一共行,要求全部完成。
out.println(您选择的性别是男人);break;case2:System.out.println(您选择的性别是女人);break;default:System.out.println(数据非法!);break;}}}工程自己建,然后你建个Test类把代码复制进去就行了。
具体的来说,Python可以将任意长的代码写在一行上(其实好像java也可以这么干)。所以行数说明不了什么问题。平均来看,Java要打行的代码,Python大约需要行代码左右。
求java小游戏源代码1、单人版五子棋,不用导入,直接新建一个mywindow类就行,然后把一下代码粘贴就Ok了。或者,直接用dos就可以了。
2、--求大神指点如何用java做扫雷小游戏详细...有源代码吗--怎么用Java做一个扫雷程序,要原创。。做好了给加--求高手写一个扫雷的JAVA代码,我愿出的悬赏或者更多。
3、先说明编程语言,我是用QB做“超级玛丽”游戏,VB做的地图编辑器。
4、最不会加注释了,不知道行不行,一共行,要求全部完成。
2024-12-29 04:21
2024-12-29 04:06
2024-12-29 03:02
2024-12-29 02:19
2024-12-29 02:13