jw编程
1. C语言编程两个数求和
用数组做,高精度算法。数组的每一个元素放一个位,如a[0]代表个位,a[1]代表十位,依此类推。
下面是算法的实现:
c[0]=(a[0]+b[0])%10; //c[x]为结果,a[x],b[x]为两个加数
overflow=(a[0]+b[0])/10; //overflow为进位的值
for(i=1;i<n;i++) //n为你两个加数的最大位数
{
c[i]=(a[i]+b[i]+overflow)%10; //a和b的第i位相加再加上第i-1位的进位的和的个位是c第i位的值
overflow=(a[i]+b[i]+overflow)/10; //a和b的第i位相加再加上第i-1位的进位的和的十位是向高位的进位
}
当然读数的时候要注意,由于位数太大,可以将其当成字符串读,再按位分离。(可能还有其他办法,不列举)
举个实例
987+87=?
个位相加c[0]=(a[0]+b[0])%10=(7+7)%10=4 ,进位 overflow=(a[0]+b[0])/10=1
十位相加c[1]=(a[1]+b[1]+overflow)%10= (8+8+1)%10=7 进位 overflow=(a[1]+b[1]+overflow)/10=1
百位相加c[2]=(a[2]+b[2]+overflow)%10=(9+0+1)%10=0 进位 overflow=(a[1]+b[1]+overflow)/10=1
。。。下面类推
2. 请问大家,传递函数里面的jw,其中w单位是什么是HZ,还是rad/s还有在matlab中它的单位是什么
弧度,matlab不会识别单位,所以单位得在你编程之前提前匹配好,matlab本身不会对单位进行匹配
3. 如下运功方程matlab怎么来编程计算,其中sgn为符号函数
符号函数不是绝对可积的函数,不存在常义下的傅里叶变换。在考虑广义函数的条件下是可求的,但不能用定义式F(jw)=∫f(t)e^{-jwt}dt来求,可以这样求:
首先已知F{δ(t)}=1,且2δ(t)=d(sgn(t))/dt。根据频域微分定理F{f'(t)}=jwF{f(t)},有F{2δ(t)}=jwF{sgn(t)},得到F{sgn(t)}=2/(jw)
4. 编程语言 JW
lay_ber.xml和lay_ber.swf同目录
5. C++编程大数加法
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
void main()
{
char atemp[10000],btemp[10000],b[10000],a[10000];
int c[10000],jw[10000];
int i,j,temp,anb,bnb,lena,lenb,lenmax,lenmin,lentemp;
int seta=0,setb=0,pd=0,tl=0,tll=0,is=0; //判断两数是否相等
scanf("%s",&atemp);
getchar();
scanf("%s",&btemp);
getchar();
lena=strlen(atemp);
lenb=strlen(btemp);
lenmax=lena>=lenb?lena:lenb;
lenmin=lenb<lena?lenb:lena;
for(i=0;i<=9999;i++)
{
jw[i]=0;
}
//都是正数或者都是负数,且位数一样的时候
if((('-'!=atemp[0]&&'-'!=btemp[0])&&(lena==lenb))||(('-'==atemp[0]&&'-'==btemp[0])&&(lena==lenb)))
{
for(i=0,j=lenmax-1;j>=0;i++,j--)
{
a[i]=atemp[j];
b[i]=btemp[j];
}
if(('-'==atemp[0]&&'-'==btemp[0])&&(lena==lenb))
{
lenmax-=1;
printf("-");
}
pd=1;
goto loop1;
}
//都是正数或者都是负数,且位数不一样的时候
if((('-'!=atemp[0]&&'-'!=btemp[0])&&(lena!=lenb))||(('-'==atemp[0]&&'-'==btemp[0])&&(lena!=lenb)))
{
if(lena>lenb)
{
for(i=0,j=lenmax-1;j>=0;i++,j--)
a[i]=atemp[j];
for(i=0,j=lenmin-1;j>=0;i++,j--)
b[i]=btemp[j];
}
if(lenb>lena)
{
for(i=0,j=lenmax-1;j>=0;i++,j--)
a[i]=btemp[j];
for(i=0,j=lenmin-1;j>=0;i++,j--)
b[i]=atemp[j];
}
for(i=0,j=lenmin;i<=lenmax-lenmin-1;i++,j++)
b[j]='0';
if(('-'==atemp[0]&&'-'==btemp[0])&&(lena!=lenb))
{
b[lenmin-1]='0'; //不知道为什么会这样
lenmax-=1;
printf("-");
}
pd=1;
goto loop1;
}
//atemp是负数,btemp是正数的时候,且长度一样的时候
if(('-'==atemp[0]&&'-'!=btemp[0])&&1==lena-lenb)
{
for(i=0,j=lenmax-1;j>=1;i++,j--)
a[i]=atemp[j];
for(i=0,j=lenmin-1;j>=0;i++,j--)
b[i]=btemp[j];
pd=2;
goto loop2;
}
//atemp是正数,btemp是负数的时候,且长度一样的时候
if(('-'==btemp[0]&&'-'!=atemp[0])&&1==lenb-lena)
{
for(i=0,j=lenmax-1;j>=1;i++,j--)
a[i]=btemp[j];
for(i=0,j=lenmin-1;j>=0;i++,j--)
b[i]=atemp[j];
pd=2;
goto loop2;
}
//一正一负,且atemp是负的时候
if(('-'==atemp[0]&&'-'!=btemp[0])&&(1!=lena-lenb))
{
if(lena>lenb)
{
for(i=0,j=lenmax-1;j>=1;i++,j--)
a[i]=atemp[j];
for(i=0,j=lenmin-1;j>=0;i++,j--)
b[i]=btemp[j];
for(i=0,j=lenmin;i<=lenmax-lenmin-1;i++,j++)
b[j]='0';
tl=1;
}
if(lenb>=lena)
{
for(i=0,j=lenmax-1;j>=0;i++,j--)
a[i]=btemp[j];
for(i=0,j=lenmin-1;j>=1;i++,j--)
b[i]=atemp[j];
for(i=0,j=lenmin-1;i<=lenmax-lenmin;i++,j++)
b[j]='0';
tll=1;
}
pd=2;
goto loop2;
}
//一正一负,且btemp是负的时候
if(('-'==btemp[0]&&'-'!=atemp[0])&&(1!=lenb-lena))
{
if(lena>=lenb)
{
for(i=0,j=lenmax-1;j>=0;i++,j--)
a[i]=atemp[j];
for(i=0,j=lenmin-1;j>=1;i++,j--)
b[i]=btemp[j];
for(i=0,j=lenmin-1;i<=lenmax-lenmin;i++,j++)
b[j]='0';
tll=1;
}
if(lenb>lena)
{
for(i=0,j=lenmax-1;j>=1;i++,j--)
a[i]=btemp[j];
for(i=0,j=lenmin-1;j>=0;i++,j--)
b[i]=atemp[j];
for(i=0,j=lenmin;i<=lenmax-lenmin;i++,j++)
b[j]='0';
tl=1;
}
pd=2;
goto loop2;
}
loop1: if(1==pd)
{
for(i=0;i<=lenmax-1;i++)
{
anb=((int)a[i])-48;
bnb=((int)b[i])-48;
temp=anb+bnb+jw[i];
if(10>temp)
{
c[i]=temp;
}
else
{
c[i]=temp%10;
jw[i+1]+=1;
if((i==lenmax-1)&&(0!=jw[lenmax]))
{
c[lenmax]=jw[lenmax];
lenmax+=1;
break;
}
}
}
for(i=lenmax-1;i>=0;i--)
printf("%d",c[i]);
printf("\n");
}
loop2:if(2==pd)
{
for(i=lenmax-1;i>=0;i--)
{
if(a[i]>b[i])
{
seta=1;
is=1;
break;
}
if(b[i]>a[i])
{
setb=1;
is=1;
break;
}
}
if(0==is)
{
printf("0\n");
exit(0);
}
if(1==tll)
lenmax+=1;
for(i=0;i<=lenmax-2;i++)
{
if((1==setb&&0==seta&&0==tl)||(1==seta&&0==setb&&1==tl))
{
anb=-(((int)a[i])-48);
bnb=((int)b[i])-48;
}
if((1==seta&&0==setb&&0==tl)||(1==setb&&0==seta&&1==tl))
{
anb=((int)a[i])-48;
bnb=-(((int)b[i])-48);
}
temp=anb+bnb+jw[i];
if(((-anb)==bnb)&&(0==jw[i])||(-anb<bnb))
{
c[i]=temp;
}
else
{
c[i]=temp+10;
jw[i+1]-=1;
}
}
lentemp=lenmax-2;
while(0==c[lentemp])
{
lentemp-=1;
}
if((1==seta&&0==setb&&0==tl&&1!=tll)||(1==setb&&0==seta&&(1==tl||1==tll)))
{
printf("-");
}
for(i=lentemp;i>=0;i--)
{
// if(0!=c[i])
// {
printf("%d",c[i]);
// }
}
printf("\n");
}
}
本程序全部自己写的。
测试结果如下:
6. 编程高手来啊!!!!!急啊!!!!!
MD5的java Bean实现
MD5简介
MD5的全称是Message-Digest Algorithm 5,在90年代初由MIT的计算机科学实验室和RSA Data Security Inc发明,经MD2、MD3和MD4发展而来。
Message-Digest泛指字节串(Message)的Hash变换,就是把一个任意长度的字节串变换成一定长的大整数。请注意我使用了“字节串”而不是“字符串”这个词,是因为这种变换只与字节的值有关,与字符集或编码方式无关。
MD5将任意长度的“字节串”变换成一个128bit的大整数,并且它是一个不可逆的字符串变换算法,换句话说就是,即使你看到源程序和算法描述,也无法将一个MD5的值变换回原始的字符串,从数学原理上说,是因为原始的字符串有无穷多个,这有点象不存在反函数的数学函数。
MD5的典型应用是对一段Message(字节串)产生fingerprint(指纹),以防止被“篡改”。举个例子,你将一段话写在一个叫readme.txt文件中,并对这个readme.txt产生一个MD5的值并记录在案,然后你可以传播这个文件给别人,别人如果修改了文件中的任何内容,你对这个文件重新计算MD5时就会发现。如果再有一个第三方的认证机构,用MD5还可以防止文件作者的“抵赖”,这就是所谓的数字签名应用。
MD5还广泛用于加密和解密技术上,在很多操作系统中,用户的密码是以MD5值(或类似的其它算法)的方式保存的,用户Login的时候,系统是把用户输入的密码计算成MD5值,然后再去和系统中保存的MD5值进行比较,而系统并不“知道”用户的密码是什么。
一些黑客破获这种密码的方法是一种被称为“跑字典”的方法。有两种方法得到字典,一种是日常搜集的用做密码的字符串表,另一种是用排列组合方法生成的,先用MD5程序计算出这些字典项的MD5值,然后再用目标的MD5值在这个字典中检索。
即使假设密码的最大长度为8,同时密码只能是字母和数字,共26+26+10=62个字符,排列组合出的字典的项数则是P(62,1)+P(62,2)….+P(62,8),那也已经是一个很天文的数字了,存储这个字典就需要TB级的磁盘组,而且这种方法还有一个前提,就是能获得目标账户的密码MD5值的情况下才可以。
在很多电子商务和社区应用中,管理用户的Account是一种最常用的基本功能,尽管很多Application Server提供了这些基本组件,但很多应用开发者为了管理的更大的灵活性还是喜欢采用关系数据库来管理用户,懒惰的做法是用户的密码往往使用明文或简单的变换后直接保存在数据库中,因此这些用户的密码对软件开发者或系统管理员来说可以说毫无保密可言,本文的目的是介绍MD5的Java Bean的实现,同时给出用MD5来处理用户的Account密码的例子,这种方法使得管理员和程序设计者都无法看到用户的密码,尽管他们可以初始化它们。但重要的一点是对于用户密码设置习惯的保护。
有兴趣的读者可以从这里取得MD5也就是RFC 1321的文本。http://www.ietf.org/rfc/rfc1321.txt
实现策略
MD5的算法在RFC1321中实际上已经提供了C的实现,我们其实马上就能想到,至少有两种用Java实现它的方法,第一种是,用Java语言重新写整个算法,或者再说简单点就是把C程序改写成Java程序。第二种是,用JNI(Java Native Interface)来实现,核心算法仍然用这个C程序,用Java类给它包个壳。
但我个人认为,JNI应该是Java为了解决某类问题时的没有办法的办法(比如与操作系统或I/O设备密切相关的应用),同时为了提供和其它语言的互操作性的一个手段。使用JNI带来的最大问题是引入了平台的依赖性,打破了SUN所鼓吹的“一次编写到处运行”的Java好处。因此,我决定采取第一种方法,一来和大家一起尝试一下“一次编写到处运行”的好处,二来检验一下Java 2现在对于比较密集的计算的效率问题。
实现过程
限于这篇文章的篇幅,同时也为了更多的读者能够真正专注于问题本身,我不想就某一种Java集成开发环境来介绍这个Java Bean的制作过程,介绍一个方法时我发现步骤和命令很清晰,我相信有任何一种Java集成环境三天以上经验的读者都会知道如何把这些代码在集成环境中编译和运行。用集成环境讲述问题往往需要配很多屏幕截图,这也是我一直对集成环境很头疼的原因。我使用了一个普通的文本编辑器,同时使用了Sun公司标准的JDK 1.3.0 for Windows NT。
其实把C转换成Java对于一个有一定C语言基础的程序员并不困难,这两个语言的基本语法几乎完全一致.我大概花了一个小时的时间完成了代码的转换工作,我主要作了下面几件事:
把必须使用的一些#define的宏定义变成Class中的final static,这样保证在一个进程空间中的多个Instance共享这些数据
删去了一些无用的#if define,因为我只关心MD5,这个推荐的C实现同时实现了MD2 MD3和 MD4,而且有些#if define还和C不同编译器有关
将一些计算宏转换成final static 成员函数。
所有的变量命名与原来C实现中保持一致,在大小写上作一些符合Java习惯的变化,计算过程中的C函数变成了private方法(成员函数)。
关键变量的位长调整
定义了类和方法
需要注意的是,很多早期的C编译器的int类型是16 bit的,MD5使用了unsigned long int,并认为它是32bit的无符号整数。而在Java中int是32 bit的,long是64 bit的。在MD5的C实现中,使用了大量的位操作。这里需要指出的一点是,尽管Java提供了位操作,由于Java没有unsigned类型,对于右移位操作多提供了一个无符号右移:>>>,等价于C中的 >> 对于unsigned 数的处理。
因为Java不提供无符号数的运算,两个大int数相加就会溢出得到一个负数或异常,因此我将一些关键变量在Java中改成了long类型(64bit)。我个人认为这比自己去重新定义一组无符号数的类同时重载那些运算符要方便,同时效率高很多并且代码也易读,OO(Object Oriented)的滥用反而会导致效率低下。
限于篇幅,这里不再给出原始的C代码,有兴趣对照的读者朋友可以去看RFC 1321。MD5.java源代码
测试
在RFC 1321中,给出了Test suite用来检验你的实现是否正确:
MD5 ("") =
MD5 ("a") =
MD5 ("abc") =
MD5 ("message digest") =
MD5 ("abcdefghijklmnopqrstuvwxyz") =
……
这些输出结果的含义是指:空字符串””的MD5值是,字符串”a”的MD5值是……
编译并运行我们的程序:
javac –d . MD5.java
java beartool.MD5
为了将来不与别人的同名程序冲突,我在我的程序的第一行使用了package beartool;
因此编译命令javac –d . MD5.java 命令在我们的工作目录下自动建立了一个beartool目录,目录下放着编译成功的 MD5.class
我们将得到和Test suite同样的结果。当然还可以继续测试你感兴趣的其它MD5变换,例如:
java beartool.MD5 1234
将给出1234的MD5值。
可能是我的计算机知识是从Apple II和Z80单板机开始的,我对大写十六进制代码有偏好,如果您想使用小写的Digest String只需要把byteHEX函数中的A、B、C、D、E、F改成a、b、 c、d、e、f就可以了。
MD5据称是一种比较耗时的计算,我们的Java版MD5一闪就算出来了,没遇到什么障碍,而且用肉眼感觉不出来Java版的MD5比C版的慢。
为了测试它的兼容性,我把这个MD5.class文件拷贝到我的另一台Linux+IBM JDK 1.3的机器上,执行后得到同样结果,确实是“一次编写到处运行了”。
Java Bean简述
现在,我们已经完成并简单测试了这个Java Class,我们文章的标题是做一个Java Bean。
其实普通的Java Bean很简单,并不是什么全新的或伟大的概念,就是一个Java的Class,尽管 Sun规定了一些需要实现的方法,但并不是强制的。而EJB(Enterprise Java Bean)无非规定了一些必须实现(非常类似于响应事件)的方法,这些方法是供EJB Container使用(调用)的。
在一个Java Application或Applet里使用这个bean非常简单,最简单的方法是你要使用这个类的源码工作目录下建一个beartool目录,把这个class文件拷贝进去,然后在你的程序中import beartool.MD5就可以了。最后打包成.jar或.war是保持这个相对的目录关系就行了。
Java还有一个小小的好处是你并不需要摘除我们的MD5类中那个main方法,它已经是一个可以工作的Java Bean了。Java有一个非常大的优点是她允许很方便地让多种运行形式在同一组代码中共存,比如,你可以写一个类,它即是一个控制台Application和GUI Application,同时又是一个Applet,同时还是一个Java Bean,这对于测试、维护和发布程序提供了极大的方便,这里的测试方法main还可以放到一个内部类中,有兴趣的读者可以参考:http://www.cn.ibm.com/developerWorks/java/jw-tips/tip106/index.shtml
这里讲述了把测试和示例代码放在一个内部静态类的好处,是一种不错的工程化技巧和途径。
把Java Bean装到JSP里
正如我们在本文开头讲述的那样,我们对这个MD5 Bean的应用是基于一个用户管理,这里我们假设了一个虚拟社区的用户login过程,用户的信息保存在数据库的个名为users的表中。这个表有两个字段和我们的这个例子有关,userid :char(20)和pwdmd5 :char(32),userid是这个表的Primary Key,pwdmd5保存密码的MD5串,MD5值是一个128bit的大整数,表示成16进制的ASCII需要32个字符。
这里给出两个文件,login.html是用来接受用户输入的form,login.jsp用来模拟使用MD5 Bean的login过程。
为了使我们的测试环境简单起见,我们在JSP中使用了JDK内置的JDBC-ODBC Bridge Driver,community是ODBC的DSN的名字,如果你使用其它的JDBC Driver,替换掉login.jsp中的
Connection con= DriverManager.getConnection("jdbc:odbc:community", "", "");
即可。
login.jsp的工作原理很简单,通过post接收用户输入的UserID和Password,然后将Password变换成MD5串,然后在users表中寻找UserID和pwdmd5,因为UserID是users表的Primary Key,如果变换后的pwdmd5与表中的记录不符,那么SQL查询会得到一个空的结果集。
这里需要简单介绍的是,使用这个Bean只需要在你的JSP应用程序的WEB-INF/classes下建立一个beartool目录,然后将MD5.class拷贝到那个目录下就可以了。如果你使用一些集成开发环境,请参考它们的deploy工具的说明。在JSP使用一个java Bean关键的一句声明是程序中的第2行:
<jsp:useBean id='oMD5' scope='request' class='beartool.MD5'/>
这是所有JSP规范要求JSP容器开发者必须提供的标准Tag。
id=实际上是指示JSP Container创建Bean的实例时用的实例变量名。在后面的<%和%>之间的Java程序中,你可以引用它。在程序中可以看到,通过 pwdmd5=oMD5.getMD5ofStr (password)引用了我们的MD5 Java Bean提供的唯一一个公共方法: getMD5ofStr。
Java Application Server执行.JSP的过程是先把它预编译成.java(那些Tag在预编译时会成为java语句),然后再编译成.class。这些都是系统自动完成和维护的,那个.class也称为Servlet。当然,如果你愿意,你也可以帮助Java Application Server去干本该它干的事情,自己直接去写Servlet,但用Servlet去输出HTML那简直是回到了用C写CGI程序的恶梦时代。
如果你的输出是一个复杂的表格,比较方便的方法我想还是用一个你所熟悉的HTML编辑器编写一个“模板”,然后在把JSP代码“嵌入”进去。尽管这种JSP代码被有些专家指责为“空心粉”,它的确有个缺点是代码比较难管理和重复使用,但是程序设计永远需要的就是这样的权衡。我个人认为,对于中、小型项目,比较理想的结构是把数据表示(或不严格地称作WEB界面相关)的部分用JSP写,和界面不相关的放在Bean里面,一般情况下是不需要直接写Servlet的。
如果你觉得这种方法不是非常的OO(Object Oriented),你可以继承(extends)它一把,再写一个bean把用户管理的功能包进去。
到底能不能兼容?
我测试了三种Java应用服务器环境,Resin 1.2.3、Sun J2EE 1.2、IBM WebSphere 3.5,所幸的是这个Java Bean都没有任何问题,原因其实是因为它仅仅是个计算程序,不涉及操作系统,I/O设备。其实用其它语言也能简单地实现它的兼容性的,Java的唯一优点是,你只需提供一个形态的运行码就可以了。请注意“形态”二字,现在很多计算结构和操作系统除了语言本身之外都定义了大量的代码形态,很简单的一段C语言核心代码,转换成不同形态要考虑很多问题,使用很多工具,同时受很多限制,有时候学习一种新的“形态”所花费的精力可能比解决问题本身还多。比如光Windows就有EXE、Service、的普通DLL、COM DLL以前还有OCX等等等等,在Unix上虽说要简单一些,但要也要提供一个.h定义一大堆宏,还要考虑不同平台编译器版本的位长度问题。我想这是Java对我来说的一个非常重要的魅力吧。
MD5算法说明
一、补位
二、补数据长度
三、初始化MD5参数
四、处理位操作函数
五、主要变换过程
六、输出结果
补位:
MD5算法先对输入的数据进行补位,使得数据位长度LEN对512求余的结果是448。即数据扩展至K*512+448位。即K*64+56个字节,K为整数。
具体补位操作:补一个1,然后补0至满足上述要求。
补数据长度:
用一个64位的数字表示数据的原始长度B,把B用两个32位数表示。这时,数
据就被填补成长度为512位的倍数。
初始化MD5参数:
四个32位整数 (A,B,C,D) 用来计算信息摘要,初始化使用的是十六进制表
示的数字
A=0X01234567
B=0X89abcdef
C=0Xfedcba98
D=0X76543210
处理位操作函数:
X,Y,Z为32位整数。
F(X,Y,Z) = X&Y|NOT(X)&Z
G(X,Y,Z) = X&Z|Y?(Z)
H(X,Y,Z) = X xor Y xor Z
I(X,Y,Z) = Y xor (X|not(Z))
主要变换过程:
使用常数组T[1 ... 64], T[i]为32位整数用16进制表示,数据用16个32位
的整数数组M[]表示。
具体过程如下:
/* 处理数据原文 */
For i = 0 to N/16-1 do
/*每一次,把数据原文存放在16个元素的数组X中. */
For j = 0 to 15 do
Set X[j] to M[i*16+j].
end /结束对J的循环
/* Save A as AA, B as BB, C as CC, and D as DD.
*/
AA = A
BB = B
CC = C
DD = D
/* 第1轮*/
/* 以 [abcd k s i]表示如下操作
a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
/* Do the following 16 operations. */
[ABCD 0 7 1] [DABC 1 12 2] [CDAB 2 17 3] [BCDA 3
22 4]
[ABCD 4 7 5] [DABC 5 12 6] [CDAB 6 17 7] [BCDA 7
22 8]
[ABCD 8 7 9] [DABC 9 12 10] [CDAB 10 17 11] [BCDA
11 22 12]
[ABCD 12 7 13] [DABC 13 12 14] [CDAB 14 17 15]
[BCDA 15 22 16]
/* 第2轮* */
/* 以 [abcd k s i]表示如下操作
a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
/* Do the following 16 operations. */
[ABCD 1 5 17] [DABC 6 9 18] [CDAB 11 14 19] [BCDA
0 20 20]
[ABCD 5 5 21] [DABC 10 9 22] [CDAB 15 14 23]
[BCDA 4 20 24]
[ABCD 9 5 25] [DABC 14 9 26] [CDAB 3 14 27] [BCDA
8 20 28]
[ABCD 13 5 29] [DABC 2 9 30] [CDAB 7 14 31] [BCDA
12 20 32]
/* 第3轮*/
/* 以 [abcd k s i]表示如下操作
a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
/* Do the following 16 operations. */
[ABCD 5 4 33] [DABC 8 11 34] [CDAB 11 16 35]
[BCDA 14 23 36]
[ABCD 1 4 37] [DABC 4 11 38] [CDAB 7 16 39] [BCDA
10 23 40]
[ABCD 13 4 41] [DABC 0 11 42] [CDAB 3 16 43]
[BCDA 6 23 44]
[ABCD 9 4 45] [DABC 12 11 46] [CDAB 15 16 47]
[BCDA 2 23 48]
/* 第4轮*/
/* 以 [abcd k s i]表示如下操作
a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
/* Do the following 16 operations. */
[ABCD 0 6 49] [DABC 7 10 50] [CDAB 14 15 51]
[BCDA 5 21 52]
[ABCD 12 6 53] [DABC 3 10 54] [CDAB 10 15 55]
[BCDA 1 21 56]
[ABCD 8 6 57] [DABC 15 10 58] [CDAB 6 15 59]
[BCDA 13 21 60]
[ABCD 4 6 61] [DABC 11 10 62] [CDAB 2 15 63]
[BCDA 9 21 64]
/* 然后进行如下操作 */
A = A + AA
B = B + BB
C = C + CC
D = D + DD
end /* 结束对I的循环*/
输出结果。
7. 如何用matlab解决百钱百鸡问题
很抱歉我的电脑上没有装matlab,我用c++给你写了一个,原理都是一样的,你自己修改一下就行,这样也可以锻炼一下你的编程能力:
intjw,jm,jc;
for(jw=20;jw>=0;jw--)
{
for(jm=33;jm>=0;jm--)
{
for(jc=99;jc>=0;jc-=3)
{
if((jw+jm+jc==100)&&(5*jw+3*jm+jc/3==100))
cout<<jw<<' '<<jm<<' '<<jc<<endl;
}
}
}
jw代表鸡翁,jm代表鸡母,jc代表鸡雏,运行结果是:
12 4 84
8 11 81
4 18 78
0 25 75
你可以检验一下,当然,代码还可以优化,你可以只使用双层循环。
8. 求助,一道ACM编程题。
运行的结果是TL?
表示给你敲了个,以后应该养成良好的代码习惯,模块化,易读懂。
------------------------------------
#include <stdio.h>
#include <string.h>
#define clear(a) memset(a,0,sizeof(a))
char A[510],B[510],Ans[510];
int La,Lb,Lans,L;
void Swap(char &a,char &b)
{
char Temp=a;
a=b;
b=Temp;
}
int Maxx(int x,int y)
{
return x>y?x:y;
}
void Turn(int L,char List[])
{
for (int i=1;i<=L;i++)
{
List[i]=List[i]-48;
}
for (int i=1;i<=L/2;i++)
{
Swap(List[i],List[L-i+1]);
}
}
void Add(char A[],char B[],int L,char C[],int &Lc)
{
int K;
char Temp;
clear(C);
for (int i=1;i<=L;i++)//求和
{
C[i]=A[i]+B[i];
}
for (int i=1;i<=L;i++)//进位
{
K=i-1;Temp=C[i];
C[i]=0;
while (Temp>0)
{
K++;
C[K]+=Temp%10;
Temp=Temp/10;
}
}
Lc=Maxx(K,L);
}
void Back(char List[],int L)
{
for (int i=1;i<=L;i++)
{
List[i]+='0';
}
for (int i=1;i<=L/2;i++)
{
Swap(List[i],List[L-i+1]);
}
}
int main(void)
{
//freopen("Data.in","r",stdin);
//freopen("Data.out","w",stdout);
clear(A);clear(B);
while (scanf("%s %s\n",&A[1],&B[1])!=EOF)
{
La=strlen(&A[1]);
Lb=strlen(&B[1]);
Turn(La,A);//翻转
Turn(Lb,B);//翻转
L=Maxx(La,Lb);
Add(A,B,L,Ans,Lans);//求和
Back(Ans,Lans);
printf("%s\n",&Ans[1]);
clear(A);clear(B);clear(Ans);
}
return 0;
}
//----------分割线--------------------------------------------------------------------------
你的程序
#include <stdio.h>
#include <string.h>
int main ()
{
char change[502];
char a[502];
char b[502];
char c[502];
int i,j,t,l1,l2,s,jw;
while(scanf("%s%s",&a,&b)==2)
{
l1=strlen(a);
l2=strlen(b);
if(l1<l2)
{
t=l1;//交换写错了!!
l2=t;//建议以后交换写成过程,减少代码量,而且可以防止错误。
l1=l2;
}
for(i=0;i<l1;i++)
{
change[i]=a[i];//发觉这个地方错了没得?
b[i]=change[i];//建议以后交换写成过程,减少代码量,而且可以防止错误。
a[i]=b[i];//错了~!!!
}
jw=0;
//这里是否要给你的i重新赋值,如果没有,那么i是从l1开始的,不知是否符合你的想法。
while(l2>0)//你写这个循环的时候可能有点混乱哇~~这个加法混乱牢,自己梳理梳理下。
{
s=(a[l1-1]-48)+(b[l2-48])+jw;//这句话首先b[l2-48]我肯定你是写错了,貌似计算
if(s>=10) //方向有点问题哈~~ 这里
{
jw=s%10;
s-=10;
}
else
jw=0;
c[i]=s+48;
l1--;
l2--;
i++;
}
while(l1>0)// 这里有点没看懂你啥意思。
{
c[i]=a[l1-1]+jw;
if((c[i]-48)==10)
{
jw=1;
c[i]='0';
}
else
jw=0;
l1--;
i++;
if(jw==1)
c[i++]='1';
}
for(;i>0;i--)
{
printf("%s",c[i-1]);
}
printf("\n");
memset(a,'\0',sizeof(a));
memset(b,'\0',sizeof(b));
memset(c,'\0',sizeof(c));
memset(change,'\0',sizeof(change));//memset()函数的使用可以参看我的程序,使用宏定义使用更为方便。
}
return 0;
}
//-----------------------------------------------
/*
看你问题里面有ACM三个字于是决定帮你找错误,今年已然悲剧,无出线,无金。写代码之前要明白自己应该干
什么,可以分为几个步骤,每个步骤怎么实现,不要直接一坨写在主函数里面。切记切记。
ACM路还长,一定要保持良好的代码习惯和个人学习习惯,祝你取得好成绩。加油@
顺便问句,令你是川大的啊?知道川大软件学院09级软件工程的信箱号码是多少不?不知道就算了,谢了。
*/
9. 用C语言编程求S=2+22+222+……+2222…2
计算思路很多比如:2+(2*10+2)+(2*10^2+2)。。(2*10^n+2)
但考虑数字长度不定,n可能会很大,那么就不能用一般整型类型存储(因为大小有限,超出就溢出了),所以采用字符串保存及按位计算。当然不能超出内存限制。
#include<stdio.h>
#include<malloc.h>
#include<string.h>
char*getNum(intlen);//获取任意位数的22222...的数字字符串
char*Addnum(char*sum,char*num);//两数字字符串按十进制数字相加后存储在sum中返回
intmain(void)
{
intlen,i;
char*num=NULL,*sum=NULL;
printf("请输入要累加的数字最高位数为:");
scanf("%d",&len);
sum=(char*)malloc(sizeof(char)*(len+1));//总和存储最大位数+2
memset(sum,'0',len+1);
sum[len]=0;
for(i=1;i<=len;i++)
{
num=getNum(i);
sum=Addnum(sum,num);
if(i==len)
printf("%s",num);
else
printf("%s+",num);
}
printf("=%s",sum);
return0;
}
char*getNum(intlen)//获取任意位数的22222...的数字字符串
{
inti;
char*num=(char*)malloc(sizeof(char)*(len+1));
for(i=0;i<len;i++)
num[i]='2';
num[i]=0;
returnnum;
}
char*Addnum(char*sum,char*num)//两数字字符串按十进制数字相加后存储在sum中返回
{
intadd,jw=0,y=0;
char*p1=sum,*p2=num;//定义2个指针,分别指向sum和num的最后一个字符地址
while(*p1++!=0);
p1--;p1--;
while(*p2++!=0);
p2--;p2--;
while(1)
{
add=*p1-'0'+*p2-'0'+jw;
jw=add/10;
y=add%10;
*p1=y+'0';
if(p2==num)
{
if(jw>0)
*(--p1)=jw+'0';
break;
}
else
{
p1--;
p2--;
}
}
returnsum;
}
10. 什么是面向对象对象,什么是面向过程,什么是面向对象思想。能详细点吗用自己的理解来说。
面向对象思想----不看后悔!
前言:
整理这份资料的目的是为了帮助朋友们能够更直观的理解面向对象的编程。让后来者能够少走一些弯路。但其中不免有许多漏洞及错误,也还请前辈提出宝贵的更改意见,毕竟交流会让我们不断的进步。
技术是日新月异的,他不会等待你的成长。技术要拿出来于别人交流,自己学是自己主观意识上的理解,有对有错!交流会让进步变得更快。我认为如果计算机 的体系结构不发生革命性的变化,我们现在所应用的程序语言也就百变不离奇踪了!学编程学的是什么?思想!精通一门编程语言(最好是面向对象的语言)后再去 搞其他的编程语言,你会发现过程是如此的行云流水!为什么?你已经把编程的思想掌握了,再去学其他的,无非是学习一种新的语法格式了。
我在这里并不是和你讨论怎么去用C++或JAVA,也不是和你讨论怎么去学他们,我要和你讨论的是怎么去理解面向对象。其中主要会涉及到“类、对象、 继承、属性、方法、静态、重载、隐藏、重构、声明、定义、初始化、赋值等”其中有许多相关技术我只会一代而过,让你有一种到此一游的意味我就达到目的了, 而更详细的技术内幕,就请参考其他相关书籍而深入研究吧!因为我只是在和你探讨如何去更好的理解面向对象!
如何去提高效率?重复使用资源,把别人的东西拿来就用。这是很不错的主意!而对于你来说,最大的资源就是信心以及积极性!好,打起精神来,让我们一同到面向对象的编程中去寻幽访胜吧!
注:文章中所有程序实例我都使用JAVA写的,当然在C++中也就大同小异了了,不同的地方我会指出!
注:文章中的正文文字用黑色,说明文字用蓝色,强调文字用橙色,批改文字用红色!
正文:
1.基本概念:
1.1 类与对象的初探
要我说,无论是面向过程的语言也好,面向对象的语言也罢,我首先要给他讲的都是类和对象!--------“这个世界是由什么组成的?”这个问题如果 让不同的人来回答会得到不同的答案。如果是一个化学家,他也许会告诉你“还用问嘛?这个世界是由分子、原子、离子等等的化学物质组成的”。如果是一个画家 呢?他也许会告诉你,“这个世界是由不同的颜色所组成的”。……呵呵,众说纷纭吧!但如果让一个分类学家来考虑问题就有趣的多了,他会告诉你“这个世界是 由不同类型的物与事所构成的”好!作为面向对象的程序员来说,我们要站在分类学家的角度去考虑问题!是的,这个世界是由动物、植物等组成的。动物又分为单 细胞动物、多细胞动物、哺乳动物等等,哺乳动物又分为人、大象、老虎……就这样的分下去了!
现在,站在抽象的角度,我们给“类”下个定义吧!我的意思是,站在抽象的角度,你回答我“什么是人类?”首先让我们来看看人类所具有的一些特征,这个 特征包括属性(一些参数,数值)以及方法(一些行为,他能干什么!)。每个人都有身高、体重、年龄、血型等等一些属性。人会劳动、人都会直立行走、人都会 用自己的头脑去创造工具等等这些方法!人之所以能区别于其它类型的动物,是因为每个人都具有人这个群体的属性与方法。“人类”只是一个抽象的概念,它仅仅 是一个概念,它是不存在的实体!但是所有具备“人类”这个群体的属性与方法的对象都叫人!这个对象“人”是实际存在的实体!每个人都是人这个群体的一个对 象。老虎为什么不是人?因为它不具备人这个群体的属性与方法,老虎不会直立行走,不会使用工具等等!所以说老虎不是人!
由此可见-------类描述了一组有相同特性(属性)和相同行为(方法)的对象。在程序中,类实际上就是数据类型!例如:整数,小数等等。整数也有 一组特性和行为。面向过程的语言与面相对象的语言的区别就在于,面向过程的语言不允许程序员自己定义数据类型,而只能使用程序中内置的数据类型!而为了模 拟真实世界,为了更好的解决问题,往往我们需要创建解决问题所必需的数据类型!面向对象编程为我们提供了解决方案。
1.2 内置数据类型与函数:
计算机程序在存储数据时必须跟踪3个基本属性为:
1. 信息存储在何处;
2. 存储的值是多少;
3. 存储的信息是什么类型的;
让我们来看看编程语言的内置数据类型都有哪些!(呵呵,这个不大好说,因为每门语言都有自己独特的数据类型,但这毕竟是少数,比如在JAVA中有 byte类型的数据,而在C++中就没有,希望你能举一反三!)比如整数”int ”,浮点类型的数据”float”!字符串”String”,以及数组还有结构体等等。然而在写程序的时候,根据需要我们会创建一个类型的变量或常量,例 如:由于我们需要创建一个整形的变量i为5,我们就可以这样做,int i = 5;而根据需要我很有可能改变i的值,也就是从新给它赋值,比如让它等与6,就可以在所需的地方改成i = 6;由此我们知道,在“值”上可以发生变化的量就叫变量。不会发生变化的量就叫做常量了,在C++中用count关键字来声明,而在JAVA中则使用 final关键字来声明。由于不同语言的声明格式不一样,这里就不做一一介绍了,详细的内容清查阅相关书籍!
在这里我们主要讨论一下函数,我们可以把函数想象成一个“实现某种特定功能的黑匣子”-------这个功能是由你来设定的,举个例子来说:现在我问 你“2+3等于多少”?我相信你能很快的回答我等于5。让我们来分析分析这句话包含什么信息!首先我要把你的大脑想象成是一个黑匣子,我并不知道也没有必 要知道你的大脑是如何工作的(也就是怎么运算的),我关心的只是我传给你的是什么信息?你对信息做了哪些处理? 以及你返回给我的是什么信息?需要提醒你一下的是每个方法都会返回一个信息给调用者的,除了构造函数外(稍候我会作详细的介绍)。我现在需要把自己当作是 一名程序员,而你呢?当然就是计算机了!计算即可没有人那么聪明,它只会按事先约好的特定的格式运行,我想让它具有如上所述的功能,我就要先定义这个黑匣 子!首先我要告诉这个黑匣子会有两个整数值给你(这就是所谓的参数,是程序员需要给黑匣子的信息),然后就要定义这个黑匣子内部实现这两个整数相加的运算 (这就是黑匣子对数据所做的加工,根据需要,你可以做任何的加工。)。最后再标注它返回给我一个同样是整型的数值(这是黑匣子返回给程序员的信息)。一个 函数就这样定义完了,让我们来看看书写格式:
int addnum(int x,int y){
return x+y;
}
具体的含义是这样的:
int /*返回值类型*/ addnum /*方法(黑匣子)名称*/ (int x,int y/*传入的参数*/){
return x+y; /*内部是想方法(实现相加运算,)并用return返回给调用者结果*/
}
首先请注意上明的“return”语句!return 关键字的含义是向调用者返回紧跟在它后面的信息!就像上面一样,因为我问你,你才会回答我,如果我不问你,你就不用回答我的!在计算机中也一样,定义好这 个函数在哪里调用呢?我只能告诉你,哪里需要就在哪里调用!当然,你可以根据需要去更改参数、返回值以及内部实现,具体到如何定义如何调用你只好去参考相 关的资料了!在这里我只是给你一个思想!
有时你会遇到这样的问题,我让你记住,我的年龄是20岁!从字面上理解,你并没有给我返回信息!然而事实上,你确实给我返回了信息,信息的内容是“无信息,也就是无返回值类型void”。具体的程序如下:
int myAge = 0;
int a=20;
void remAge(int a){
myAge=a;
}
具体的函数说明如下:
int myAge =0; //定义并初始化我的年龄为0;
int a=20; /*定义变量a等于20*/
void /*返回值类型为无返回值类型*/ remAge /*函数名称*/(int a /*传入的参数*/){
myAge=a; //内部实现方法,注意,没有return返回!!!
}
关于函数的话题还有很多很多,这里就不一一介绍了,我的目的是让你知道函数是怎么一会事儿!为下面的讨论作铺垫!
1.3 指针以及引用:
指针及引用是在C++中有的,JAVA中没有。JAVA中取消了对内存的操作,随之而来的事也取消了操作符重载的操作。不过在稍候我还是会介绍一些操 作符重载的功能等。引用主要还是用在函数参数的传递上。所以我在这里就不做过多的介绍了。他们很实用,有兴趣的同学可以参阅C++相关书籍。
1.4 运算符及控制语句:
还是自己看看相关书籍吧,这里就不再熬述了!
2.深入探讨面向对象:
2.1“类型”的内部细节:
有了上面的知识,我们现在就可以深入的挖掘类的内部实现了。所有的知识点我都会围绕着类与对象展开,在此之前,我希望你能够确信对以上所介绍的基本内容已完全掌握了!
是的,面向对象的编程语言最大的特色就是可以编写自己所需的数据类型,以更好的解决问题。我想我必须要帮你搞清楚“类,对象,属性,方法它们之间的关 系”!就像我前面所说的,人这个“类”是什么也做不了的,因为“人类”只是一个抽象的概念,它不是实实在在的“东西”,而这个“东西”就是所谓的对象。只 有人这个“对象”才能去工作。而类呢?类是对象的描述!对象从类中产生出来!此时,对象具有类所描述的所有的属性以及方法。-------一定要理解这句 话!!!
也许你已经有些不知所措了,没关系!好好的回味一下,我再举个例子!例如电视机,电视机都有工作原理图,那么什么叫电视机呢?只要它能够实现工作原理图的 所有功能的物体,我们都叫它电视机。你想想是不是这么一回事儿?可是,电视机原理图是不能工作的,也就是这个原理图不能收看节目,只有电视机这个“实体 ——即所谓的对象”才能收看节目,也就是说,从类生成出对象之后才算得上是真正的有意义!才能开始工作。此时,电视机拥有电视原理图所描述的所有的属性及 方法!明白了吧,呵呵!
我先前介绍过,类是属性与方法的集合。而这些属性与方法可以被声明为私有的(private),公共的(public)或是受保护(protected)的,他们描述了对类成员的访问控制。下面我分别做一下介绍:
1. 公共的(public):把变量声明为公共类型的之后,那么就可以通过对象来直接访问,一切都是暴露无遗的!也就是说,你的信用卡密码别人也能够直接得到。
2. 私有的(private):如果把变量声明为私有的情况就好多了,想要得到我的信用卡密码,对象必须要调用专用的方法才能够得到。
3. 受保护的(protected):介绍继承时再讨论。
4. 默认控制访问符(friendly)://JAVA中有而C++中没有。
为了实现数据的封装,提高数据的安全性,我们一般会把类的属性声明为私有的,而把类的方法声明为公共的。这样,对象能够直接调用类中定义的所有方法,当对 象想要修改或得到自己的属性的时候就必须要调用以定义好的专用的方法才能够实现。你想想,你会把你的信用卡密码公布出来嘛?呵呵!所以,我们提倡的是: “对象调方法,方法改属性”;
2.2通过实例看内存分配:
说了这么多,让我们来看一个实例吧!比如:现在我们要编写某家公司员工管理系统,你认为最合适的数据类型是什么?我认为是员工个人!但是在面向过程的 语言中,这样做是不允许的,因为它只能使用语言中的内部数据类型!而员工不在这个内部数据类型之内!也许有人会说可以用C语言中的struct,好注意! 毕竟它是类的基础!如果你以前是一名面C或B的程序员,请你忘掉这些,让我们一起看看如何用类来实现这一切吧!
某家公司的员工是人类的一个特殊群体,它除了具备人类的所有特性与方法外,它还有额外的特性与方法,比如她有她的工资、信用卡密码、作息时间等等,这 些特性以及工作内容,工作量等等这些方法。而在计算机中我们该如何定义这个类呢?下面我将写出它的格式,让你看看在计算机中它是张什么样子的!
/*在此我需要再次声明的是,我用的是JAVA格式,在语法格式上它与C++大不相同!许多细节以及内部操作都有诸多区别,而在思想上确实大同小异的*/
//employee.java
public class employee{
private String name; //员工姓名
private int age; //员工年龄
private char sex; //员工性别
private float emolument; //员工薪水
private boolean lunch; //员工午餐
//……等等
public void heater(){ //这个方法是用来加工员工的午餐
lunch = true;
}
public void setName(String a){ //这个方法是修改员工的姓名
name= a;
}
public String getName(){ //这个方法是得到员工的姓名
return name;
}
//……等等
}
这样我们就定义完了我们所需要的数据类型。现在,让我们来看看它能够干什么以及怎么工作!
我想要做的是,工作室里有一个光杆司令叫“jingwei”,我修改它的名字后对对它进行输出,看看我是怎么做的吧!
注意:请仔细观察对象是如何调用方法的,它使用了“.”操作符!事实上是这样的,对象调用公共的属性或方法时就会使用“.”操作符。
然而在C++中,如果定义一个同类型的指针,该指针调用此对象的方法时,就会使用“->”操作符。更详细的内容清参阅相关书籍了!
//workstation.java
import java.awt.Graphics;
import java.applet.Applet;
public class workstation extends Applet{
private employee jingwei ; //对象的声明,此时并不分配内存!
public void init(){
jingwei = new employee(); /*此时创建对象会调用构造函数,稍候介绍*/
jingwei.setName(“jw”); //设置我的名字
}
public void paint(Graphics g){
g.drawString("my age is "+jingwei.getName(),10,10);//显示我的年龄
}
}
输出结果是:
my name is jw
这串字符串是在输出窗口的x坐标轴为10 px , y坐标轴为10 px的位置。
我现在要做的是,把上面的程序做个大解剖,让你能够看清楚它到底是怎么一回事儿!(我可不时带你去看里面的汇编,呵呵,那个我也不会:)
首先还是来看看我们自定义的数据类型employee,在应用的时候它和int类型的数据没什么两样,一样的需要创建变量(对象),只不过前者是咱自 己定义的,而后这是它内置的。Employee这个类中有许多属性,也有许多方法。而此时,我们不能直接用我们所创建出来的对象调用它的属性进行修改。因 为它是private受保护类型的!我要想修改我的姓名我就要用对象调用setName()这个方法,而我想得到我的姓名就要调用getName()这个 方法。我们完全是按照航线来行走的,这个航线就是“对象调方法,方法改属性”
好的,我真的相信你已经明白了这是怎么一回事儿了!呵呵!仰起航帆,继续前行!
现在让我们一起来看看workstation这个类。这是个主类,和C++中的main()函数的味道差不多。其中,在JAVA中,一个文件只允许有而且必须有一个主类,这个主类用public来声明!他就跟C++中必须要有一个main()函数是一样的。
让我们来看看这个类中的第一条语句!private employee jingwei ;这条语句的作用是声明一个employee的对象jingwei(在C++中就不用声明了)。我想要和你说的是“声明”与“定义”之间的区别。声明只是 告诉计算机将要有这样的一个变量(对象),在内存中它并不为这个变量(对象)分配内存!而只有在定义的时候才会给这个变量(对象)分配内存。(需要说明一 下的是init()方法是完成初始化操作的,在此处定义对象,为对象分配内存。start()方法用来启动浏览器的主线程,paint()方法来显示 Apple的界面。这些是Applet程序所需的,至于Application程序就不需要了,当然了,C++中也不需要他们。关于他们的详细内容清参阅 相关书籍)
紧接着就开始定一个对象了,对jingwei这个对象进行操作才会有实际的意义。千万不要有这种想法:“试图对类进行操作!”就像前面我说的,电视机 原理不能看电视一样!这是毫无意义的!看这条语句jingwei = new employee();它的意思就是定义一个employee类型的对象jingwei。此时,我想告诉你的是:“jingwei这个对想拥有了些什 么”。它拥有了类所描述的所有的属性及方法。下面我一一给你列出来:
/*所有的employee对象都拥有这些属性。每创建一个对象就会从新分配一块内存来存放相应对象的这些属性。我的意思是每个对象都有自己“独特”的一份*/
private String name; //员工姓名
private int age; //员工年龄
private char sex; //员工性别
private float emolument; //员工薪水
private boolean lunch; //员工午餐
/*所有的employee对象都拥有这些方法。但在内存中只有一份*/
public void heater(){ //这个方法是用来加工员工的午餐
lunch = true;
}
public void setName(String a){ //这个方法是修改员工的姓名
name= a;
}
public String getName(){ //这个方法是得到员工的姓名
return name;
}
/*但是,实际上在创建jingwei这个对象时计算机只给这个对象的所有的属性分配了内存,而并没有给方法分配内存。方法只有一个,是属于所有的对象的,所以无论创建了多少个对象,计算机只会为一个方法分配一块内存。*/
我想我还是举个例子吧,不然你非晕倒不可。呵呵!
看我这条语句“private boolean lunch;”公司不管午餐,每个员工都需要带饭。我们现在这样想,公司的空间是所有的内存容量,你的办公桌就是计算机中的内存中的一部分(每个员工都有 一份,是在创建对象时分配的)。你把午饭带到了公司,放在了你的办公桌上。“午饭”占据了你的办公桌的一角(占了你自己“对象”的一块内存容量)。这份午 饭只属于你自己,同样别人的也只属于她自己!所以每个员工(对象)都需要一快空间(内存)来存放自己的午餐(属性)。在计算机中也是这样的,每创建一个对 象,就会在内存中从新分配一块内存来放“午餐——lunch”这个属性(对象所拥有的所有的属性)。
计算机只会为对象的属性分配内存。因为每个对象的都不一样!就像你往公司带的午饭和我往公司带的午饭不一样是一个道理!但方法就不同了。早晨带的饭中 午就凉了,你需要用微波炉来加热。微波炉可不用你带,公司就有(只占公司的一块空间),它放在了午餐桌上。你想想,微波炉属于谁的?它属于所有员工的!因 为每个员工都可以用它。而不必每个员工都带一份。由此可见,每个员工(对象)都有一份午饭(属性),但所有的员工(对象)只一个微波炉(方法)。所有的员 工(对象)都可以通过这个微波炉(方法)来改变自己午餐(属性)的冷热状态。殊途同归!在计算机中也就是这样,方法只有一份,供所有的对象使用!而属性是 每个对象一份,因为每个对象的都不一样。别和我说你还不明白,不然我会撞墙的,呵呵:)
2.3深入探讨函数:
2.3.1构造函数、默认构造函数、 缺省构造函数
对于上面的实例,它已经能完成绝大部分工作了,但它还是不完善的,还有许许多多的细节等到我们去完善!也许有的同学已经注意到了,当我创建完 “jingwei”这个对象时,这个对象的所有的属性都是空的,也就是说:这个对象的姓名是未定的、年龄是未定的、性别是未定的、薪水是未定的、午餐也是 未定的。而我们想把这些属性都添加上去,就还要用对象调用相应的方法,去一个个修改!天啊,这简直是太麻烦了!有没有什么好方法能够在我们创建对象的同时 就完成了对属性赋值的操作呢?哦不,应该说是对属性的初始化呢?当然没问题了,这就需要所谓的构造函数!
构造函数是类中最特殊的函数,它与析构函数的功能正好相反!
从特征上来说:1.它是编程语言中唯一没有返回值类型的函数。
2.它的名称与类的名称必须要完全相同。
3.它必须被声明为公共(public)的类型
4,可以对构造函数进行重载。
5.它在创建对象是自动被调用。
从功能上来说:1.它是对类中的属性进行初始化。
其实,对于上面的程序来说我们没有自己定义构造函数。但是,在这种情况下,系统会自动为我们定义一个“默认构造函数”。他会把数值变量自动赋值为0, 把布尔行变量赋值为false等等(但在C++中,默认构造函数不初始化其成员)。如果程序员定义了构造函数,那么系统就不会再为你的程序添加一个缺默认 造函数了。(在这里,我们提倡的是自己定义构造函数,而不是用系统的默认构造函数)
还是看个实例吧!这样比较清楚一些!
//employee.java
public class employee{
private String name; //员工姓名
private int age; //员工年龄
private char sex; //员工性别
private float emolument; //员工薪水
private boolean lunch; //员工午餐
//……等等
public employee(){ //这个就是“默认”构造函数
name = “jw”; //设置员工姓名
age = 20; //设置员工年龄
sex = “M”; //设置员工性别
emolument = 100; //设置员工薪水
lunch = false; //设置员工午餐
}
public void heater(){ //这个方法是用来加工员工的午餐
lunch = true;
}
//……等等
};
这样,在我们创建“jingwei”这个对象的同时,它的所有的属性也被初始化了!显然,这大大的提高了工作效率,但是,它还是不符合要求。想想看, 如果我们现在创建这个类型的第二个对象的时候会发生什么事情?告诉你,除了对象的“名”(这个名称不在是对象属性中的名称,而是对象本身的名称)不一样 外,其所有的“属性值”都一样!比如:现在我们创建第二个对象flashmagic,然而我会发现这个对象的所有的属性和jingwei这个对象的所有的 属性完全相同。而我们只能在用对象的方法去改变着写属性了!很显然,这种方法不大好!我们需要一种方法在创建对象的时候为对象的属性赋予“我们想要的 值”。
相信你也看到了,默认构造函数就显得无能为力了。我们需要的是带参数的构造函数,在创建对象时,我们把参数传给构造函数,这样就能完成了上述的功能!口说无凭,还是来看个实例吧:
//employee.java
public class employee{
private String name; //员工姓名
private int age; //员工年龄
private char sex; //员工性别
private float emolument; //员工薪水
private boolean lunch; //员工午餐
//……等等
public employee(String n,int a,char s,float e,boolean l){ //看这个构造函数
name = n; //设置员工姓名
age = a; //设置员工年龄
sex = s; //设置员工性别
emolument = e; //设置员工薪水
lunch =l; //设置员工午餐
}
public void heater(){ //这个方法是用来加工员工的午餐
lunch = true;
}
//……等等
};
这样一来,在创建对象的同时我们就可以给他赋予我们想要的值,很显然,这可就方便多了。哦,对了!还没有告诉你怎么创建呢!哈哈,往前翻几页你会看到这句话:
jingwei = new employee();这是创建一个对象,而我们把它改成
jingwei = new employee("jingwei",20,'M',100,false);这样一来,所有的工作都完成了,呵呵!(在创建对象的同时赋予了我们想要的“初值”)
2.3.2重载构造函数:
我还是先把概念给你吧,让你有个认识,随后我们在进行论述。
在JAVA中:
1. 函数重载是一个类中声明了多个同名的方法,但有不同的参数个数和参数类型。
2. 函数重构是指在子类中声明与父类同名的方法,从而覆盖了父类的方法。重构解决了子类与父类的差异问题。(在讨论到继承时我会详细说明)
在C++中:
1. 数重载的概念一样。
2. 重构的概念可就不一样了,C++中功能更为庞大的虚函数。更详细内容这里就不错过多介绍了!
其实关于重载的概念你并不陌生,在编程中相信你也接触过。呵呵!让我们来举个操作符重载的例子你就会明白了,(JAVA中不支持这个功能)我们定义三个整数变量:
int i1=2, i2=3,i3=0;
i3 = i1 + i2;
此时i3=5;加号实现了两个数相加的运算功能。然而我们现在要定义三个字符串变量:
String str1=”jing”, str2=”wei”,str3=””;
str3 = str1 + str2;
此时str3 = “jingwei”;加号实现了两个字符串相加的运算功能。同样是加号,既可以把两个整型的变量加在一起,也可以把两个字符串类型的变量加在一起。同一个 操作符实现了不同的功能------这就是所谓的操作符重载(嘿嘿,我说你一定见过吧:)!不就好像是汉语中的一词多意一样!我需要说明一下的是,C++ 中的操作符重载可没有这么简单。比如,我们可以对两个自定义类型的对象进行相加的运算,进行赋值的运算。这样书写简洁明了,而且非常实用。当然,关于操作 符重载的话题太多了,有兴趣再看看书吧!
我们把操作符的话题在转到函数上来,我们一直强调的是“对象调方法”------对象其实调的是方法的“名称”。而我们现在要对方法进想重载,也就是 定义多个相同名称的函数,这样计算机在调用的时候不会混淆嘛?我想应该不会的,呵呵,因为仅仅是函数名称相同,而我们在调用函数时会把参数传递给他的。既 是没有参数也是一种参数传递参数的信息(信息为无参数)!然而由于参数类型、参数数量、返回值类型不同我们就可以对相同名称的函数进行区分