多态的应用

标签(空格分隔): Java


多态的体现
多态就是同一个实体,同时具有多种形式

//方便理解所以用的中文
class 战士 extends 英雄 {
    public void show() {
        System.out.println("正义审判");
    }
}
public class 英雄 {
    public void show() {
        System.out.println("英雄的通用攻击方法");
    }
    public static void main(String[] args) {
        英雄 x = new 战士(); // 这个就是多态,比如我可以叫它为战士,也可以叫它为英雄,这样就是一个类型的多种形态
        // 多态在程序中的体现:父类或接口的引用指向了自己的类对象
    }
}

简单理解就是父类的引用实现了子类的对象。

#多态的好处体现

abstract class Hero{//这个是抽象父类
     abstract void attack();**

     public static void main(String[] args) {
            //这样通过方法传入父类而调用子类的方法就是多态好处的体现了
            method(new Warrior());
            method(new Master());
        }
     //调用传入的对象的方法
     public static void method(Hero hero) {
         hero.attack();
     }
}
class Warrior extends Hero{
    void attack() {
        System.out.println("战士放大招");
    }
}
class Master extends Hero{
    void attack() {
        System.out.println("法师发射一颗冰球");     
    }
}

正是因为多态这样的好处,提高了代码的扩展性,后期出现的功能,可也以被之前的程序所执行,所以多态是使用的非常多的!

以上是我个人关于多态的应用的想法,欢迎大家提供宝贵的意见!

从概念到业务来看 To B 和 To C 产品区别在哪?

自从互联网火了以后,一大堆 o2o,b2b,c2c 的产品出现,这些名词也渐渐为人熟知,但很多人对这些产品的理解也是停留在概念上,实际上绝大部分人用的都是 To C(也写作2c)产品,比如微信,qq 等。今天丁丁就站在设计狮/产品汪的角度从概念到设计给大家分析一下 To B 和 To C 产品的区别,为方便理解,以下举例会采取两个极端进行对比。

概念

字面上的意思都很明确:To B 就是 To business,面向企业或者特定用户群体的面商类产品;To C 就是 To customer,产品面向消费者。平常大家讨论比较多的是 To C 类产品,因为大家都在使用,且设计师很多在从事 To C 类产品的设计工作。

To C 产品是发现用户需求,定义用户价值,并准确的推动项目组达成这一目标;而 To B 产品是根据公司战略或工作需要,构建生态体系,或者推动将流程系统化,提高效率。说白了就是 To C 产品是你去挖掘用户需求,是创造,从无到有;To B 产品是公司战略或相关方给你提出要求,产品经理将这类「线下已有的需求」系统化,达到提高现有流程的效率的目的。

逻辑流程

从上面的概念来看,To C 产品更注重的是用户体验,而 To B 产品更注重的是功能价值以及系统性,所以在逻辑上如果极端简化一个 To C 类产品的任务流程,可能是这样的:

流程

一个机智的用户来使用是这样:

一个不太机智的用户来使用是这样:

然后看一个 To B 类产品,信息架构复杂的时候,如果设计师没有达到逻辑清晰,那设计出来的任务流程可能是这样的:

呵呵

这时,
萌萌的用户会:-_-
默默的用户会:呵呵……
凶狠的用户会:设计师你过来我保证不砍死你……

所以做 ToB 类产品设计,一定不能像写散文一样,随心而至,随时下笔,得像写议论文那样,做足功课,想清楚重点和逻辑,脑中成图,再动手画稿。(图来自@设计师Yoyo)

学习成本

做产品设计的一个基本要求,就是要保证用户学习成本足够低,低到没有最好。做 To C 产品这个目标很明确,也很容易靠拢,而做 To B 产品很难。比如一个中国电信客服的界面,一个PC界面密密麻麻上百个功能,业务员完全凭借自己的记忆力和习惯来进行操作,没有太多的任务流清晰度可言。这样的产品使用,是需要一定时间的学习才能达到基本使用,学习成本肯定不低。

客服系统
还有不少 To B 产品,需要有专门的培训和讲解,才能勉强让新用户开始使用。这个时候,如果单纯以学习成本低到没有来要求 To B 类产品,非常难。信息架构复杂起来,是很难通过认知设计、视觉设计、交互流程简化来解决学习成本高的问题。有几个点可以帮助到,一是灵活有效的提示,二是充足有价值的用户测试,三是深刻理解业务,设计师的业务理解水平接近架构师和产品经理的水平,才能从体验侧做一定范围的有效改动,来帮助产品的可用性得到提升。

学习成本

业务理解度

做复杂信息架构产品,最难的就是业务理解入门。例如做微信、QQ 音乐等产品,设计师相对好入手,因为设计师本身也是用户群体。而复杂信息架构产品一般不是给普通用户使用的,而是给一个特定群体的用户使用的,大部分情况下设计师与这个特定群体是没有交集的。例如设计师接到一个任务,做银行交易系统,首先,设计师没有在银行工作过,对银行交易流程基本不了解;第二,设计师完全不知道使用这个交易系统的用户的心理模型、工作状态、用户场景、喜怒哀乐。如果这个银行交易系统是给尼日利亚的某个银行做的,可能设计师连当面和用户交流的机会都没有。

理解业务

所以做这类产品时,动工前,设计师大部分时候业务理解度无限趋近于 0。最好的方式就是建议设计师能自己跑去真实使用场景做做自己的用户访谈,例如到用户群体做一天的跟踪访谈、用户深访、任务流程记录、用户痛点记录等,这些真实的感受和体验带来的价值远远大于架构师或者产品经理给设计师描述带来的价值。

亲子体验

以上就是从概念到业务两者的对比,简单总结就是 To C 产品的用户直接是用户个人,所以更关注人性或者说用户体验,强调的是刚需,痛点,高频,体验,而 To B 产品存在的前提就是为了满足「组织完成业务信息化」的需要,所以 To B 的产品非常关注组织和业务,核心是功能服务、效率以及系统。

当然还可以继续从其他维度继续对比,但丁丁觉得没必要,以上基本可以弄懂两者的区别,最重要的还是工作实践。讲到产品,就离不开产品经理,下面我们主要从产品经理在这两类产品设计中体现的能力来看下两者的区别。

To C 产品对产品经理的最大要求

很好的用户嗅觉,能准确提炼用户真实需求,为产品的市场化方向和用户利益寻求到一个平衡点;需要有一定的运营基础,能根据用户反馈不断优化产品;优秀的 To C 产品经理还是个优秀的数据分析师,能够根据数据结果反推产品功能。

做 To C 的产品经理一般都乐于分享,经常可以看到他们跟老板 pk,性格不会很闷。他们还会懂那么一点运营、营销、品牌策略,并会将其体现在产品形态中。

沟通能力
另外,To C 的产品和开发是同一个团队,目标一般都是一致的,他们朝着同一个产品方向去努力即可,所以你会看到 To C 产品经理的项目推动力要求没有 To B 产品经理的推动力要求那么高。To C 产品经理还需要拥有很高的交互设计能力和用户体验感知,这里所说的交互设计和体验感知都必须围绕公司战略和产品方向进行展开,To C 的初级产品经理最容易犯的错误是把太多的时间抠在产品的设计细节上。说具体些,就是把产品的交互设计和 UI 设计看的太重,几乎大部分的时间都花在 Axure 原型图的设计上了,而忽视了产品方向和产品本身应该重点考虑的地方。

To B 产品对产品经理最大的要求

To B 端的产品经理需要具备优秀的需求梳理能力和推动能力,在大公司尤其明显。你可以看到,To B 端产品的需求是服务于公司战略、或者服务于线下已有的流程,产品经理要做的是理解和实施公司战略,构建生态系统,或者将已有流程系统化,也就是说需求主要的来源并不是普通用户。

构建完整生态,或者提升效率,就是 To B 产品经理的价值所在。你的某个推动,会改变行业,如微信公众号的产品经理,提出的商家管理生态,就为线下商家提供了完整的互联网化转型解决方案。

完整生态
做 To B 产品的产品经理一般都拥有慎密的逻辑思维,他们的性格相比 To C 产品经理也稍显沉闷,他们大多数理性过头。他们能够很耐心的坐下来理解公司或合作部门提出的要求,其实他们同时担任任着产品经理和需求分析师的角色,优秀的 To B 产品经理如果转型,具备做大公司的 IT 系统咨询分析师的能力。

2018是00后的成年元年,他们将陆陆续续走向社会。那么,00后们有着什么样的独特价值观和消费观念?

《腾讯00后研究报告》显示,00后这代平均每个数低于1,他们不像80或90后那样跟兄弟姐妹分的爱和资源。90后平均存款约815元,00后平均存款约1840元,很多从拥有出国看世界的机会。他们的热爱更多出于自发,62%的00后表“对感兴趣的领域投很多时间和钱”。
来源:腾讯社交广告
























































end

如题:
判断 101-200 之间有多少个素数,并输出所有素数
判断素数的方法:用一个数分别去除 2 到 sqrt(这个数 ),如果能被整除, 则表明 此数不
是素数,反之是素数。
//思路分析:1.先找出有几个变量 发现101-200之间可以设为变量i 找出X的最大值 i<=200;
发现2- sqrt(这个数 )之间可以设为变量y 找出y的最大值 y<=i;
2.

       //先找出有几个变量  发现101-200之间可以设为变量x 找出X的最大值 x&lt;=200;
     for( i = 101 ;i &lt;=200; i ++)
     {
    //发现2- sqrt(这个数 )之间可以设为变量y 找出y的最大值 y&lt;=i;
     for(int j = 2 ; j &lt;= i;j++)
     {
     //如果能被整除, 则表明 此数不是素数,反之是素数。
     if( i % j ==0) break;
     else{ printf(&quot;%d&quot;,i);
            break;
            }
     }//结束内部循环
     }//结束外部循环
     如题

一个数如果恰好等于它的因子之和,这个数就称为 "完数 "。例如 6=1+2+ 3 编程找
出 1000 以内的所有完数。
//思路分析:1.先找出几个几个变量 比较明显时的到1000以内的数,所以最大值为1000 i = 1;i<=1000;
2. 观察6=1+2+ 3 发现可以定义一个变量 j ,j的最小值时1开始 ,最大值时到i为止 所以j = 1; j<=i;
3.找出因子 发现 从1开始i为止如果真被整除的就是因子 得出 i % j == 0;j就是因子
4.通过观察 6=1+2+ 3 发现完数i是因子的累加和 需要定义一个sum;因为统计时的i的累加值所以就放在外层循环内 每次验证完重新计算
//先找出几个几个变量 比较明显时的到1000以内的数,所以最大值为1000 i = 1;i<=1000;
for(int i = 1 ; i <= 1000 ;i++)
{ int sum=0;

//发现可以定义一个变量 j ,j的最小值时1开始 ,最大值时到i为止 所以j = 1; j&lt;=i;
for(int j = 1; j &lt;= i ; i++)
{
//找出因子 
    if(i % j ==0 )  
    {
    sum+=j;//为了找出完数
    if(sum == i)
    printf(&quot;%d&quot;,i);//打印完数
    }
}//结束内层循环

}//结束外层循环

4、打印出杨辉三角形特征是,它的两条斜边都是由数字 1 组成的,而其余的数则是等于它肩上的两个数之和。
1.三角形的两边斜边上都是数字1,而其余额数都等于它肩上额两个数字相加
2.杨辉三角具有对称性(对称美,与首末两端“等距离”额两个数相等
3.每一行额第二个数就时是这行的行数
4.所有行的第二个数够成等差数列
5.第N行包含n+1个数
//思路分析 1.角形的两边斜边上都是数字1,而其余额数都等于它肩上额两个数字相加;所以要记录下第几行的下标 中有 10行10列
这里采用二级数组 int a[][] = new int[10][10];(这里我用的java写的我)
观察空个的关系 (这里我用#号表示)
########## 第一行 i = 0 , j =9;
######### 第二行 i = 1, j= 8;
######## 第三行 i = 2, j = 7;
####### 第四行 i = 3, j = 6;
###### 第五行 i = 4, j = 5 ;
##### 第六行i = 5 , j = 4
#### 第七行 i = 6 , j = 3;
## 第八行 i = 7 , j = 2;
# 第九行 i =8 , j = 1; //得出结论 j<=9-i;(这里是为了)让零填上

    观察数字的形状可以(把数字看成*)
      *                     第一行 i = 0;j = 0;
      **                    第二行 i = 1;j = 1 ; 
      ***                   第三行 i = 2;j = 2;
      ****                  第四行 i = 3;j = 3;
      *****                 第五行 i = 4;j = 4;
      ******                第六行 i = 5;j = 5;
      *******               第七行 i = 6;j = 6
      ********              第八行 i = 7; j = 7;
      *********             第九行 i =8 ; j=8;
      **********            第十行 i =9 ; j=9;
                                 观察得出j&lt;=i;(这是三角型的)



for(int i = 0; i&lt; 10 ; i++) //10行
{
 //全部填上不管0为了不打印出来
 for( int j = 0 ; j &lt;= 9 - i; j++)
 {
  a[i][j] = 0;
 }

for(int j = 0; j&lt;= i; j++)
{
//三角形的两边斜边上都是数字1,     而其余额数都等于它肩上额两个数字相加(先解决两边为1的情况)
    if(j == 0|| j == i)a[i][j] = 1;
    //3.每一行额第二个数就时是这行的行数
    else if(j == 1) a[i][j] = i; 
    //余额数都等于它肩上额两个数字相加
    else a[i][j] = a[i-1][j-1]+a[i-1][j];

}//内部循环
}//外部循环

//打印图片

for(int i = 0; i &lt;10; i++)
    {   
        for(int j = 0 ; j&lt;10; j++){
            if(i==0&amp;&amp;j==0)//这是为了第一行的数字看起来协调的 
                System.out.print(&quot;\t   &quot;);
        if(a[i][j]==0)//如果是0就不要打印出来打印空格补位为了美观
            System.out.print(&quot; &quot;);
         if(a[i][j]!=0)//不是0就打印出来
            System.out.printf(&quot;%3d&quot;,a[i][j]); //把数字打印出来
             if(i == j)//如果是打印的是最后一个就换行
            System.out.print(&quot;\n&quot;);
        }//结束内层循环

}//结束外层循环


5、编写函数,将一个字符串的全部有效元素逆。函数原型可声明为“void reverseStr( char * str ) ;”,参数 str 为指向字符串的指针。

//解题思路: 先要知道str的长度然后进行首尾交叉换 ,换次数为长度/2次;
 void reverseStr( char * str ) ; //函数声明
 int main()
 {
    return 0;
 }
 /*void reverseStr(char*str)//函数实现

{

 char temp;
 char*p = str; //用指针指向字符串的首地址
int  count = 0;
 for(int i = 0;*( p + i) != '\0' ; i++)
 {
     count++;//算出个数
 }
 p = NULL;// 指针指向空
for(int i = 0 ;i&lt; count / 2;i++)
{
//进行首尾交叉交换次数为长度/2次;
    temp  = str[i];
    str[i] = str[count-1-i];
     str[count-1-i] = temp;
}
printf(&quot;%s&quot;,str);//输出结果

}
6、编写函数,将一个十进制数转换成一个二进制数(提示:将转换后的二进制数各位的值依次存储在一个一维数组中,要输出时,只要逆序输出这个数组各元素的值即可)。函数原型可声明为:“int transformToBin( int dnum, int bin[ ] ) ;”,参数 dnum 是要转换的十进制数,bin 是存储转换后的二进制值的数组(逆序存储的),返回值是 bin 数组中元素的个数。

int transformToBin(int dnum, int **bin);//函数声明(让我皮下我就要浪)

int transformToBin(int dnum, int **bin)//函数定义
{
int count = 0; //用于计算要分配空间的个数
int i = 0; //用来记录bin[]数组的下标
int temp ; //临时指针
temp=(int
)malloc(sizeof(int));//分配空间
if(dnum 0)
{
(temp) /= 2;
count++;
}
// 分配空间大小
bin =(int
)malloc(count);
//将二进制的结果传入数组
//将二进制的结果传入数组
while(dnum>0)
{
bin[i] =dnum%2;
dnum /= 2;
i++;
}
//打印看下有问题吗?
for(int j=0;j<count;j++)
{
printf("%d",bin[j]);
}
//逆序
for( int j = 0;j < count/2; j++)
{

         (*temp)=bin[j];
         bin[j] = bin[count-1-j];
         bin[count-1-j] =(*temp);
 }
 printf(&quot;\n&quot;);
//输出逆序后结果
 for( i  = 0 ; i &lt; count; i++)
 {
       printf(&quot;%d&quot;,bin[i]);
 }
 free(bin);//没用释放掉
free(temp);//没用释放掉

return count; //返会分配的个数数
 //
 // 思考问题如何表示 -号?

}

7、编写函数,将数组 s1 中的全部奇数都复制到数组 s2 中。函数原型可声明为:“int copyTo( int
* s1 , int n, int * s2 ) ; ”,参数 s1 和 s2 为指向两个数组的指针,n 为数组 s1 中元素的个数,
返回值为复制完成后 s2 中元素的个数。

int copyTo( int * s1 , int n, int ** s2 );//函数声明 继续浪(上面已经浪死了我还是要浪 主要是想节约空间啊)

int copyTo( int * s1 ,int n, int ** s2 ) //函数定义
{
int count=0;//奇数个数
//计算奇数个数
for(int i= 0;i<n;i++)
{
if(s1[i]%2!=0)
continue;
else count++;
}
s2 =(int)malloc(count);//分配空间

  for(int i= 0,j = 0 ;i &lt; n; i++) //j用于记录s2 的下标
{

      if(s1[i] %2!=0)//找个奇数
      {
            s2[j] =s1[i];//把奇数逐个放入S2
            j++;
      }
}
//输出结果
for(int i = 0 ;i&lt;count;i++)
{
    printf(&quot;%d \t&quot;,s2[i]);
}

   return count;//返回数字

}

int transformToBin(int dnum, int **bin);//函数声明
int main()
{
int **** a = null; //这里只有一个星号(网站打打不出一个星号);
transformToBin(15,&a);
//这个问题在于一旦超过4个数组就报内存错误但是结果是正确的?如果把15改为16就显示程序异常!
}
int transformToBin(int dnum, int **bin)//函数定义
{
//编写函数,将一个十进制数转换成一个二进制数(提示:将转换后的二进制数各位的值
//依次存储在一个一维数组中,要输出时,只要逆序输出这个数组各元素的值即可)。函数原
//型可声明为:“int transformToBin( int dnum, int bin[ ] ) ;”,参数 dnum 是要转换的十进制数,
//bin 是存储转换后的二进制值的数组(逆序存储的),返回值是 bin 数组中元素的个数。

int count = 0; //用于统计要分配的空间个数
int i=0;//用于记录bin数组的下标
int *temp ;// 临时变量指针
temp=(int*)malloc(1);//分配空间
int temp2=dnum;//用于判断是否为负数
if((*temp)0)
 {
    bin[i] =dnum%2;
    dnum /= 2;
     i++;
 }
 for(int j=0;j&lt;count;j++)
 {

    printf(&quot;%d&quot;,bin[j]);
 }

 //逆序
for( int j = 0;j &lt; count/2; j++)
 {

         (*temp)=bin[j];
         bin[j] = bin[count-1-j];
         bin[count-1-j] =(*temp);
 }
    printf(&quot;\n&quot;);
 //输出逆序后结果
 for( i=0 ; i&lt;count;i++)
 {
        printf(&quot;%d&quot;,bin[i]);
 }


free(bin);//释放
free(temp);//释放已经没用了

return count;

//bug 思考如何处理负数的情况???
//思路先取绝对值
//在末尾加上二进制的1把最高位改为1;

}

如题:
1、设有数组定义:char array[] = “china”,则数组 array 所占的空间为( )。
A.4 个字节
B.5 个字节
C.6 个字节
D.7 个字节
//1.首先array[]中有5个字节的长度,
2.char形数组都是以’\0’结束的所以总的有6个字节。
联想:是否 每种类型的数组都以’\0’结束?

2、以下程序的输出结果是( )
int num = 10;
if(num++ > 10 || ++num 10(因为为后置++,所以num与10先比较 条件为假 然后num现在为11了 继续执行||后面的 )++num < 10 (因为++num,所以是先加1 此时num为12 与10比较)都不成立所以执行 后面的else (先–在打印因此结果为11);(注意:如果
为后置++是先打印再++;)

3、下面程序运行结果是( )。
y=5; x=14; y=((x=3y,x+6),x-1);
printf("x=%d,y=%d",x,y);
A. x=27,y=27
B. x=12,y=13
C. x=15,y=14
D. x=y=27
//思路分析:此题的问题点在于 y=((x=3
y,x+6),x-1);首先先看括号里的x=3*y;运算结果为 x =15,计算机继续运行x+6 值为21然后继续运行x-1,值为15-1。注意点()的优先级别和取的时最后的值。

4、设有以下函数:void fun(int n,char * s){}
则下面对函数指针定义和赋值均正确的是()
A. void(pf)();pf = fun;
B. void *pf();pf=fun;
C. void *pf();
pf=fun;
D. void (pf)(int,char);pf=&fun;
//思路分析:C中定义函数时可以省略参数部分但是如果有参数类型,一定要与申明时的类型一致,所以先排除D。接下来就是指针函数问题,函数名是这个函数的首地址,所以fun是个地址再排除C. 括号优先级 ()的运算级别高于
,得出A

5、以下正确定义一维数组的选项是()
A. int a[5]={0,1,2,3,4,5};
B. char a[] = {’0’, ’1’, ’2’, ’3’, ’4’, ’5’, ’\0’};
C. char a = {‘A’,’B’,’C’};
D. int a[5] = “0123”;
//思路分析: A ,数组声明是5个int类型的元素,但是却给了6个元素
c. 属于字符类型不属于数组 联想问题:C 的a=???
D.属于类型不匹配

问题分析

1.首先得明白什么是素数,素数就是只能被1和它本身整除的数成为素数(最开始我在写程序是都没分清楚这是个啥,所以左后写出来的程序是错的,“此处应该有个捂脸的表情”);所以,数与商和余数之间的关系有三种,(数 / 因素 = 商····余数)即:
a)、数 = 因数 时,商1余0;输出 该数为素数
b)、数 != 因数 时,商不为1余不为0;因数+1继续循环
c)、数 != 因数 时,商不为1余为0;输出 该数不是素数

2.明白了素数的概念后,就得思考我们需要时什么变量来表示;

int i;      //定义一个循环变量来表示我们要找的素数,范围101-200之间,所以i的初值101而不是0开始
int sqrt;       //定义一个循环变量来表示因素,初值为2
int mod;    //取模
int quotient;//商

3.执行判断,用数i除以因数sqrt,如果余数等于0,说明数i的因数除了1和它本身还是有sqrt,所以该数不是素数,跳出循环

for(i = 101; i < 200; i++)  //外层循环表示我们要找的素数
{
    for(sqrt = 2; sqrt < i; sqrt++)     //内层循环表示数的因子,因为任何数除以1都等于它本身,所以不判断为1的情况
    {

    }
}

4.通过取模来判断i能否除尽sqrt,如果模为0,能除尽,则该数已经能判断为不是素数,跳出该循环;否者模不为0时,不能除尽,sqrt累加到数本身,即商为1时,该数为素数

if(mod == 0)
{
    break;
}
else
{
    sqrt++;
}

注:此处应明白continue和break的用法;continue是跳出当前循环执行循环条件,而break则是结束循环。

参考程序:

#include <stdio.h>
#include <stdlib.h>

int main()
{
    /*判断 101-200 之间有多少个素数,并输出所有素数
    判断素数的方法:用一个数分别去除 2 到 sqrt(这个数 ),如果能被整除, 则表明 此数不
    是素数,反之是素数。*/

    int i;      //定义一个循环变量来表示我们要找的素数,范围101-200之间,所以i的初值101而不是0开始
    int sqrt;       //定义一个循环变量来表示因素,初值为2
    int mod;    //取模
    int quotient;//商
    int count = 0;

    printf("101-200之间的素数有:");
    for(i = 101; i < 200; i++)  //外层循环表示我们要找的素数
    {
        for(sqrt = 2; sqrt < i + 1; sqrt++)     //内层循环表示数的因子
        {
            mod = i % sqrt;
            quotient = i / sqrt;

            if(mod == 0)
            {
                if(quotient == 1)
                {
                    printf("%d,",i);
                    count++;
                    break;
                }
                else
                {
                    break;
                }
            }
            else
            {
                continue;
            }
        }
    }
    printf("\n\n共有%d个素数\n",count);

    return 0;
}

  • a) 如果用户的输入匹配彩票的实际顺序,奖金为 10000 美元;
  • b) 如果用户输入的所有数字匹配彩票的所有数字,奖金为 3000 美元;
  • c) 如果用户输入的一个数字匹配彩票的一个数字,奖金为 1000 美元;
  • d) 注意:两位数字中有可能为 0.如果一个数字小于 0,就假设这个数字;以 0 开始。例如程序中数字 8 被作为 08 处理,数字 0 被作为 00 处理

问题分析:

1.根据题目判断,系统随机生成一个两位数,所以就需要用到随机函数:

#include <time.h>

2.根据要求,用户输入的数字,需要与系统随机产生的数字进行一位数一位数的判断,所以,引用下列语句,把用户输入的数字

int num1;       //用户输入的两个数字
int num2;

3.题目中有要求,将用户输入的数字与随机产生的数字进行位比,所以就需要拆分随机数的个位和十位

int a,b,j;      //a为随机数的十位,b为随机数的个位,j为随机两位数

4.随机数的取值范围是0-32767,但是我们只需要两位,用取模的方式来获得我们需要的两位数

srand(time(NULL));
j = rand() % 100;
a = j / 10;    //将随机数的十位赋值
b = j % 10;    //将随机数的个位赋值

5.根据题目的要求,可以用if语句进行描述
if函数的结构:

if(条件)
    {
        表达式
    }
else
    {
        表达式
    }
  • a)因为随机函数产生的数是大于0的两位数的整型,所以先判断用户输入的数是否复合要求,符合要求,继续用随机数进行对比,不符合就退出程序。
if(num1 >= 0 && num1 < 10 && num2 >= 0 && num2 < 10)
  • b)在符合要求的情况下,用户的输入的数与随机数有四情况:两个数完全相同;两个数顺序不同但是交叉相同;两个数中有一位数相同;两个数完全不同;
if(num1 == a && num2 == b)//两个数完全相同
(num1 == a || num1 ==b) && (num2 == a || num2 ==b)//两个数顺序不同但是交叉相同
num1 == a || num1 ==b || num2 == a || num2 ==b//两个数中有一位数相同

参考程序:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>


int main()
{   /*开发开一个玩彩票的游戏,程序随机产生一个两位数的彩票,提示用户输入一个两位数
    (可以做相关的判断),然后按照下面的规则判定用户是否能赢:
    a) 如果用户的输入匹配彩票的实际顺序,奖金为 10000 美元
    b) 如果用户输入的所有数字匹配彩票的所有数字,奖金为 3000 美元
    c) 如果用户输入的一个数字匹配彩票的一个数字,奖金为 1000 美元
    d) 注意:两位数字中有可能为 0.如果一个数字小于 0,就假设这个数字以 0 开始。例
    如程序中数字 8 被作为 08 处理,数字 0 被作为 00 处理*/

    int num1,num2;    //用户输入的数字
    int a,b,j;          //a为随机数的十位,b为随机数的个位,j为随机两位数


    srand(time(NULL));
    j = rand() % 100;
    a = j / 10;
    b = j % 10;

    printf("中奖号码:%d\n",j);        //输出一个两位的随机函数
    printf("请输入你的第一个数字:");
    scanf("%d",&num1);
    printf("请输入你的第二个数字:");
    scanf("%d",&num2);

    if(num1 >= 0 && num1 < 10 && num2 >= 0 && num2 < 10)            //用户输入数的范围
    {
        if(num1 == a && num2 == b)          //用户的输入匹配彩票的实际顺序
        {
            printf("恭喜你中了一等奖,奖金为 10000 美元。\n");
        }
        else if((num1 == a || num1 ==b) && (num2 == a || num2 ==b))     //用户输入的所有数字匹配彩票的所有数字
        {
            printf("恭喜你中了二等奖,奖金为 3000 美元。\n");
        }
        else if(num1 == a || num1 ==b || num2 == a || num2 ==b)         //用户输入的一个数字匹配彩票的一个数字
            {
            printf("恭喜你中了三等奖,奖金为 1000 美元。\n");
            }
        else
        {
            printf("很遗憾,你没有中奖!\n");
        }
    }
    else
    {
        printf("很遗憾,你没有中奖!\n");
    }

    return 0;
}

阅览了RUDECRAB朋友的三篇文章,受教颇多。相比之下,个人在写代码的时候总会想着先写出代码实现功能,然后再回头一个一个地用注释去解释这行代码的含义和我写的动机。
但功能的实现一旦细分出几个小的部分,注释其实是自然而然就写出来了,就好像一个一个零件对应的词条,自动组成了产品的一篇说明书。而不是产品组装好后,再一个一个地指着其中的零件说:“这个是干什么的”。

不过我也按照自己思路写了万年历的代码,有这样几个已知的问题:
1. 所有代码写一个类中,比较冗长
2. 其中部分循环嵌套结构,是完成了两种以上的功能,算是不符合“一个方法做一件事”的原则
3. 注释说的不明不白,格式也有点问题,也许就我看得懂

但我也发上来,算是抛砖,也方便对比学习,期待RUDECRAB朋友的下一篇笔记。

import java.util.Scanner;

/**
 * 
 * @function 万年历
 * @author Pix
 * @date 2019年3月29日
 * @place 学堂
 * @version 1.0.0
 * @copyright Pix
 *
 */
public class Calendar {
    /*
     * 程序的主入口
     */
    public static void main(String[] args) {
        // 创建扫描器类对象input接收用户的键盘输入
        Scanner input = new Scanner(System.in);
        //在控制台显示字符串:********************欢迎使用万年历********************
        System.out.println("********************欢迎使用万年历********************");
        //可以无穷循环输入并显示万年历的功能
        while (true) {
            //创建整型变量year和month用于接收用户输入的年份与月份
            int year;
            int month;
            System.out.println();

            //接收用户合法的输入年份(1900-9999),0退出系统,其他数字要求重新输入
            do {
                System.out.print("请输入年份(输入0退出):");
                year = input.nextInt();
                //输入内容为0时,退出系统
                if(year == 0)return;
            } while (year < 1900 || year > 9999);

            //接收用户合法的输入月份(1-12),其他数字要求重新输入
            do {
                System.out.print("请输入月份:");
                month = input.nextInt();
            } while (month < 1 || month > 12);
            System.out.println();

            //输入成功后,开始打印当月月历
            //此处使用的字体中汉字显示为其他字符的2倍宽
            System.out.printf("%-6s%-6s%-6s%-6s%-6s%-6s%-6s\n", "星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六");

            /*
             *  两个重要的中间变量:均为整型
             *  days用来记录用户输入的年月1日距离1900年1月1日的天数
             *  day用来记录用户输入的当年当月有多少天
             *  初始均为0
             */
            int days = 0;
            int day = 0;
            //将用户输入年份元旦距离1900年元旦的天数加给days
            //从1900年开始,到year的前一年结束,需要将天数累加到days
            for (int y = 1900; y < year; y++) {
                //如果这一年是闰年则加366天
                if (y % 4 == 0 && y % 100 != 0 || y % 400 == 0)
                    days += 366;
                //否则加365天
                else
                    days += 365;
            }
            //嵌套判断,用于将当年当月之前的月份天数加给days
            //同时根据月份,把对应的天数赋值给day
            //如果月份不是1月,则days加上1月的天数
            if (month != 1) {
                days += 31;
                //算上之前的条件,如果月份不是2月,则days加上2月的天数
                if (month != 2) {
                    //如果year对应闰年,则加29天,否则加28天
                    if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0) {
                        days += 29;
                    } else {
                        days += 28;
                    }
                    //算上之前的条件,如果月份不是3月,则days加上3月的天数
                    if (month != 3) {
                        days += 31;
                        //算上之前的条件,如果月份不是4月,则days加上4月的天数
                        if (month != 4) {
                            days += 30;
                            //算上之前的条件,如果月份不是5月,则days加上5月的天数
                            if (month != 5) {
                                days += 31;
                                //算上之前的条件,如果月份不是6月,则days加上6月的天数
                                if (month != 6) {
                                    days += 30;
                                    //算上之前的条件,如果月份不是7月,则days加上7月的天数
                                    if (month != 7) {
                                        days += 31;
                                        //算上之前的条件,如果月份不是8月,则days加上8月的天数
                                        if (month != 8) {
                                            days += 31;
                                            //算上之前的条件,如果月份不是9月,则days加上9月的天数
                                            if (month != 9) {
                                                days += 30;
                                                //算上之前的条件,如果月份不是10月,则days加上10月的天数
                                                if (month != 10) {
                                                    days += 31;
                                                    //算上之前的条件,如果月份不是11月,则days加上11月的天数
                                                    if (month != 11) {
                                                        days += 30;
                                                        //算上之前的条件,那这个月只能是12月
                                                        //12月的天数
                                                        day = 31;
                                                    } else
                                                        //算上之前的条件,那这个月只能是11月
                                                        //11月的天数
                                                        day = 30;
                                                } else
                                                    //算上之前的条件,那这个月只能是10月
                                                    //10月的天数
                                                    day = 31;
                                            } else
                                                //算上之前的条件,那这个月只能是9月
                                                //9月的天数
                                                day = 30;
                                        } else
                                            //算上之前的条件,那这个月只能是8月
                                            //8月的天数
                                            day = 31;
                                    } else
                                        //算上之前的条件,那这个月只能是7月
                                        //7月的天数
                                        day = 31;
                                } else
                                    //算上之前的条件,那这个月只能是6月
                                    //6月的天数
                                    day = 30;
                            } else
                                //算上之前的条件,那这个月只能是5月
                                //5月的天数
                                day = 31;
                        } else
                            //算上之前的条件,那这个月只能是4月
                            //4月的天数
                            day = 30;
                    } else
                        //算上之前的条件,那这个月只能是3月
                        //3月的天数
                        day = 31;
                } else
                    //算上之前的条件,那这个月只能是2月
                    //2月的天数,如果是闰年为29天,否则为28天
                    day = (year % 4 == 0 && year % 100 != 0 || year % 400 == 0) ? 29 : 30;
            } else
                //算上之前的条件,那这个月只能是1月
                //1月的天数
                day = 31;
            /*
             * 了解了days可以用来判断这个月从星期几开始
             *  了解了day可以判断这个月有几天要打印
             */


            //由于1900年1月1日是星期一,所以days%7对应的数字就是这一天离星期一有几天(往后算的方式)
            //相当于从星期一打印几个天数的间隔
            //但是万年历的显示是从星期日开始的,所以days+1再取余,方便星期日不打印间隔
            for (int i = 0; i < (days + 1) % 7; i++)
                //因为"星期X"三个字本身占6个空格的宽度,所以间隔占9个宽度
                System.out.printf("%-9s", "");

            //根据day的天数打印日历,换行是每7天换一次,第一次换行是打印到第一个周六之后
            //第一次换行前有(days+1)%7个间隔,所以再打印7 - (days+1)%7个数字换行即可,i从0开始。
            for (int i = 0; i < day; i++) {
                System.out.printf("%-9d", i + 1);
                if (i % 7 == 6 - (days + 1) % 7)
                    System.out.println();
            }
            //循环执行前先换行
            System.out.println();
        }
    }

}

看见中间很壮观的嵌套分支了吗?刚写完的时候很得意,因为我用这个实现了当月1日到当年元旦的天数days计算,顺便还把当月天数也赋值给day了。
但这个当年内天数days的计算,用switch结构不带break的技巧,可以省掉好几个大括号的行数。
不过用一个switch把days和day都算出来,好像判断条件有点多,我写了一下发现从2月往后每个月都要判断闰年,不太适合。但这是因为试图”一个方法实现两个功能”的原因,分开写都很简单,合在一起就麻烦很多。

最后要做一个总结和思考是吗?

嗯————人们是为了偷懒而进步的。

第一次写,不足和疏漏之处还请见谅

前提:

已通过运行jdk-8u201-windows-x64.exe程序安装Java
安装目录选择默认,一般为C:\Program Files\Java

开始配置

  1. 右键“计算机”图标,菜单中点击“属性”,进入“系统”界面

  2. 点击系统界面左侧栏的“高级系统设置”,点击“环境变量”

  3. 修改“系统变量”栏中的Path变量,双击编辑

    变量值末尾增加字符 ;%JAVA_HOME%\bin;%JAVA_HOME%\jre\bin;
    (注:保留分号以和之前字符分隔)

  4. 在“系统变量”栏中新建名为JAVA_HOME的变量:
    变量名:JAVA_HOME
    变量值:JDK安装位置
    JDK默认安装位置为C:\Program Files\Java\jdk1.8.0_201

  5. 在“系统变量”栏中新建名为CLASSPATH的变量
    变量名:CLASSPATH
    变量值:.

至此,Java环境配置完成。

检验方法

  • 运行cmd.exe控制台
    分别输入java,javac,java -version命令,显示JDK相关信息



    则说明安装与配置成功。