JAVA基础知识学习笔记(流程控制、数组)

来源:互联网 发布:hilook撕拉面膜知乎 编辑:程序博客网 时间:2024/05/18 23:53

第四章、流程控制和数组

       无论哪种语言都会提供两种基本的流程控制结构:分支结构和循环结构。分支结构用来选择性的执行,循环结构用来根据条件重复执行某段代码。

       Java提供的:

       分支结构:if和switch

       循环结构:while、do while和for,JDK1.5还提供了一种新的循环foreach循环,能以更简单的方式遍历集合、数组的元素。此外,还提供了break和continue来控制程序的循环结构。

       if-else语句,一定要先处理包含范围较小的情况,比如判断一个人是少年、青年、中年还是老年,应该从老年开始判断。

       switch语句要注意:1、expression表达式的数据类型只能是byte、short、char和int。2、不要省略break;

                   switch(expression)

                    {

                        case 条件1:

                                执行语句;

                                 break;

                                          case 条件1:

                                 执行语句;

                                 break;

                         default:

                                 执行语句;


               }

       循环语句一般要包括,初始化语句、循环条件、循环体和迭代语句。

       for循环和while、do while 语句不同,由于while、do while 循环的迭代语句紧跟着循环体,因此如果循环体不能完全执行,如使用continue来结束本次循环,则循环迭代语句不会执行。但for语句的循环迭代语句并没有和循环体在一起,不管是否使用continue结束本次循环,不会影响迭代语句的执行。

       for循环允许指定多个初始化语句(但是只能有一个声明语句,初始化多个变量,必须是同一个类型),循环条件可以是一个包含逻辑运算符的表达式,如for(int b=0,s=0,p=0;b<10&&s<4&&p<20;p++)

       continue结束本次循环,开始下次循环

       break完全结束一个循环,跳出循环体,开始执行循环之后的代码。

       注意:在多层嵌套循环时,可在外层循环前加label:,然后通过break label;来直接跳出外层循环。continue也有类似用法。

       return不是专门用于跳出循环的,他的功能是结束一个方法。若方法里有循环,自然也可以结束这个循环。


          Java数组

      Java数组既可以存储基本类型的数据,也可以存储引用数据类型的数据,只要所有数组元素具有相同的类型即可。

      注意:数组也是种数据类型,它本身是一种引用类型,如int是基本类型,int[]就是引用类型,类型不同。

      定义一个数组,推荐使用int[] a;来表示,不再推荐使用int a[];

      数组是一种引用类型的变量,因此使用它定义一个变量时,仅仅表示定义了一个引用变量(也就是定义了一个指针),这个引用变量尚未指向任何有效的内存空间,所以还没有内存空间来存储数组,这个数组也就不能使用,定义数组时不能指定数组的长度。只有对数组进行初始化后才能使用!

      所谓初始化,就是为数组的元素分配内存空间,并为每个数组元素赋初始值。

      数组初始化有两种方式:

      静态初始化:初始化时由程序员显式的指定每个数组元素的初始值,由系统决定需要的数组长度。

      动态初始化:初始化时程序员只指定数组长度,由系统为数组元素分配初始值。


为什么有栈内存和堆内存之分?

     当一个方法执行时,每个方法都会建立自己的内存栈,在这个方法内定义的变量将会逐个放入这块栈内存中,随着方法的执行结束,这个方法的内存栈这就自然销毁了。

     当我们在程序中创建一个对象时,这个对象将被保存在运行时数据区中,以便反复利用(因为对象的创建成本通常比较高),这个运行时数据区便是堆内存。堆内存中的数据不会随着方法的结束而被销毁,即使方法结束后,这个对象仍然可能被另一个引用变量所引用(方法的参数传递时很常见),只有当一个对象没有任何引用变量引用它时,系统的垃圾回收机制才会在合适的时候回收它。

      数组引用变量是访问堆内存中数组元素的唯一方式,即如果堆内存中不会再有任何引用变量指向此数组,则这个数组将成为垃圾,该数组所占的内存将被系统的垃圾回收机制回收。因此,为了让垃圾回收机制回收这个数组所占的内存空间,则可以讲该数组变量赋为null,也就切断了数组引用变量和实际数组之间的引用关系,实际数组也就成了垃圾。


      

public class ArrayInRam{public static void main(String[] args){//定义并初始化数组,使用静态初始化int[] a={5,7,20};//定义并初始化数组,使用动态初始化int[] b=new int[4];//输出b数组的长度System.out.println("b数组的长度为:"+b.length);//循环输出a数组的元素for(int i=0;i<a.length;i++){System.out.println(a[i]);}//循环输出b数组的元素for(int i=0;i<b.length;i++){System.out.println(b[i]);}//因为a是int[]类型,b也是int[]类型,所以可将a的值赋给b//也就是让b的引用指向a引用指向的数组b=a;//再次输出b数组的长度System.out.println("b数组的长度为:"+b.length);}}

       运行上述代码后,可以看到,先输出b数组的长度为4,然后依次输出a、b数组的每个元素,然后输出b数组的长度为3。看起来数组b的长度变了,但这是一个假象!!

       要时刻牢记,定义并初始化一个数组后,在内存里分配了两个空间,一个空间用于存放数组的引用变量(栈内存),另一个用来存放数组本身(堆内存)。

     

       当执行b=a;代码时,系统将会把a的值赋给b,a和b都是引用类型变量,存储的是地址。因此将a的值赋给b后,就是让b指向a所指向的地址,即:

      

       可见a、b变量都指向了第一个数组,此时第二个数组失去了引用变成了垃圾,只有等待垃圾回收系统来回收他,但他的长度依然不会改变,直到他消失。

       我们来看看数组初始化的过程:

public static void main(String[] args){//定义一个int[]类型的数组变量int[] Arr;//动态初始化数组,数组长度为5Arr=new int[5];//采用循环方式为每个数组元素赋值for(int i=0;i<Arr.length;i++){Arr[i]=i+10;}}

        执行int[] Arr;时,仅定义了一个数组变量,在栈内存中定义了一个空引用,这个引用并未指向实际有效的内存空间,也当然无法指定数组的长度,此时内存中的存储如下:

          

       

         当执行Arr=new int[5];动态初始化后,系统将负责为该数组分配内存空间,并分配默认的初始值:所有元素都被赋为0。

        

          循环为每个数组元素赋值后,此时每个元素的值变为程序指定的值。、



五、面向对象

       类可以认为是一种自定义的数据类型,可以用类来定义变量,所有使用类定义的变量都是引用变量,即类是引用数据类型。

       Java提供private、protected和public三个访问控制符来实现良好的封装。

      对于一个类,可以包含三种常见的成员:构造器、属性和方法,三种成员都可以定义0个或多个。类中各成员的定义顺序没有任何影响,各成员间可以相互调用,但是static修饰的成员不能访问没有static修饰的成员。

      构造器是一个类创建对象的根本途径,Java通过new关键字来调用构造器,从而返回该类的实例。如果一个没有构造器,则这个类将无法创造实例,因此系统会为每个类提供一个默认的构造器,一旦程序员自己定义了构造器,则默认构造器失效。

       static是个特殊的关键字,他可以用来修饰方法、属性等成员。static修饰的成员表示他是这个类所共有的,而不是属于该类的单个实例,因此也把static修饰的属性和方法称为类属性、类方法。不使用static修饰的属性和方法属于该类的单个实例,而不是属于这个类,也称之为实例属性、实例方法。注意:静态成员不能直接访问非静态成员。

       static修饰的方法和属性,可以通过类.方法/属性或者实例.方法/属性来调用。没有使用static来修饰的方法和属性,只能通过实例来调用。

       构造器是一个特殊的方法!定义构造器的语法格式与定义方法的语法格式很像,定义构造器的语法格式如下:

       [修饰符] 构造器名(形参列表)

      {        //零条到多条可执行的语句组成的构造器执行体

      }

      构造器名必须和类名相同。但是构造器不能定义返回值的类型,也不能用void,如果为构造器定义了返回值,编译时不会出错,但是Java会把这个所谓的构造器当成方法来处理。实际上类的构造器是有返回值的,当我们用new关键字来调用构造器时,构造器返回该类的实例,把该类的实例作为构造器的返回值,因此构造器的返回值的类型总是当前类,因此无需定义返回值的类型。必须注意,不能在构造器中显式的使用return来返回当前的对象,因为构造器的返回值是隐式的。

     person p=new person();

    

         栈内存里面的引用变量并未真正存储对象里面的属性数据,对象的属性数据实际上存放在堆内存中。引用型变量仅仅是指向该堆内存中的对象。从这个角度来看,引用型的变量与C语言中的指针很像,他们都是存储一个地址值,都是通过这个地址值来引用到实际的对象。当一个对象创建成功后,这个对象将被保存在堆中,Java程序不允许直接访问堆中的对象,只能通过该对象的引用来操作对象,不管数组还是对象,只能通过引用来访问他们。

        堆里面的对象可以有多个引用,即多个引用变量指向同一个对象,如person p2=p;

        Java提供了this关键字,this关键字是一个对象的默认引用,this总是指向调用该方法的对象,根据this出现的位置的不同,this作为对象的默认引用有两种情形:

        构造器中引用该构造器执行初始化的对象

        在方法中引用调用该方法的对象

        this关键字最大的作用就是让类中的一个方法访问该类的另一个方法或属性。

        例如:

public clas Dog{public void jump(){System.out.println("正在执行jump");}public void run(){Dog d=new Dog();d.jump();Systme.out.println("正在执行run方法");}}

       这种方法可以实现,但是会产生两个Dog对象!这里有两个问题:

      1、run()方法调用jump()方法时是否一定需要一个Dog对象?

          答案是肯定的,因为没有static修饰的方法,必须使用对象来调用。

      2、是否一定需要重新创建一个Dog对象呢?

          答案是否定的,因为当程序调用run()方法时,一定会提供一个Dog对象,这样就可以直接使用这个Dog对象,无需重新创建新的Dog对象。

         所以我们需要在run()方法中获得调用该方法的对象,通过this关键字就可以。


public clas Dog{public void jump(){System.out.println("正在执行jump");}public void run(){this.jump();Systme.out.println("正在执行run方法");}}

           this可以代表任何对象,当this出现在某个方法体中时,它所代表的对象是不确定的,但它的类型是确定的,它所代表的对象只能是当前类。只有当这个方法被调用时,它所代表的对象才被确定下来,谁在调用这个方法,this就代表谁!

        这种同一个对象两个方法之间的依赖很常见,Java允许对象一个成员直接调用另一个成员,即可以忽略this.

 

public void run(){         jump();         System.out.println("正在执行run方法");}

            对于static修饰的方法而言,可以使用类来直接调用方法,但是如果在static修饰的方法中使用this关键字,则这个关键字无法指向合适的对象。所以static修饰的方法中不能使用this引用,static修饰方法不能访问不使用static修饰的普通成员,这与前面所说的静态成员不能直接访问非静态成员的结论一致。

      

public class StaticAccess{public void info(){System.out.println("这是个简单的info方法!");}public static void main(String[] args){//因为main方法是静态方法,而info是非静态方法,所以调用会出错info();}}
         编译时会提示错误:无法从静态上下文中引用非静态方法info(),因为info()是对象相关的方法,而不是类相关的方法,因此必须使用对象来调用该方法。main()方法中直接调用info()方法时,相当于使用this作为该方法的调用者,而static修饰的方法中是不能使用this引用的。

         如果确实需要在静态方法中调用普通方法,则只能重新创建一个对象,

 

//重新创建一个对象来调用info()方法new StaticAccess().info();

        



























         

原创粉丝点击