java基础
java的工作方式;
我们要做的事,就是编写源代码文件,然后由javac编译程序把文件进行编译,得到字节码文件,然后再在java虚拟机运行此程序;
在java中程序都是类组成的 ,其中有个类中有main方法,这是java程序的入口,java程序在这里开始运行,
在java中变量的类型有两种,基本类型和引用类型;
基本类型的概念可以比喻成杯子,要事先声明杯子的大小,之后才能把值存到相应的杯子中,但是引用类型就不一样了,一般引用类型变量的内存大小是相同的,它会因不同的java虚拟机而不同,然后在引用类型变量存储的不是对象的实际值;而是堆空间的地址(我理解的是在一些new出来的对象被放在的内存的某个地方;变量只是存储了这个地址));
数组犹如杯架;
1.声明一个int数组变量,数组变量是数组对象的遥控器;
int[] nums;
2.创建大小为7的int数组;并把它赋给之前声明的int[] 的nums变量;
nums = new int[7];
数组也是对象;
java注重类型;一旦声明数组是什么类型;数组元素必须是声明的那种类型;
对象的行为;
对象实例,在一个类中有变量,有方法,当一个方法需要参数时,就需要在调用的时候传入相应类型的值,因为java是强类型的;
还有在java中传递参数时是按值传递的,也就是说是拷贝一份值过去,如果参数时基本类型,在方法中改变该参数的值,不会影响到原来变量的值,但是如果是引用类型,因为传递的是地址,所以在方法内改变变量的时候,会改变对象的值;
get和set方法;是对变量的引用;
封装:
封装的基本原则:将你的实例变量标记为私有的,并提供公有的getter与setter来控制存取动作;
数组对象的行为;
变量的初始化;初始值是0或者null;
实例变量和局部变量的区别:
1.实例变量是声明在类中,而不是方法中;
2.局部变量声明后,并没有自动的初始化。在使用前,必须手工的初始化,不然编译器会报错;
3.局部变量是声明在方法中的;
变量的比较:使用==来比较两个基本数据类型变量是否相等,或者判断两个引用是否引用同一个对象;
使用equals()来判断两个对象是否在意义上相等;
继承和多态:
子类会继承父类的实例变量和方法;在子类中如果想在某一个方法中调用父类的方法;却不覆盖父类的方法还要增加自己的行为,可以用super.xxx();
子类会继承父类所有public类型的实例变量和方法;但不会继承父类所有private类型的变量和方法;藕,
当某个方法在子类中被覆盖过,调用这个方法会调用覆盖过的版本;
多态的运行;
原本情况下,等号两边是要相同的类型,例如:Dog myDog = new Dog();
但是在多态下,引用与对象可以是不同的类型。 Animal myDog = new Dog();
这两者的类型不相同,引用变量的类型被声明为Animal,但对象是Dog。
运用多态时,引用类型可以是实际对象类型的父类;
多态不仅体现在这个变量的定义里,参数和返回类型也可以多态!;
如果你想要防止特定的方法被覆盖,可以将该方法标识final;
子类要覆盖父类的方法必须是要参数 返回类型 权限 全部一样;
接口与抽象类;
接口是多态和java的重点;
Connection是个接口,它声明个变量,赋值的语句里返回的就是实现该接口的子类的实例。
设计抽象类型很简单:abstract class Canine extends Animal{};
有些类不希望被初始化,也就是不想被new xxx();就可以把它声明为抽象类;
抽象类除了被继承之外,没有其他用途了;
除了类之外,也可以把方法标识为abstract,代表一定要被子类覆盖才可以;如果方法是抽象的,那么那个类也一定是抽象的;还必须实现所有抽象的方法;
构造器与垃圾收集器;
这里主要讲述了变量内存的问题;局部变量会变放在栈中,调用方法的时候也会在栈中,正在执行的方法会在栈顶上,
实例变量是存储在该对象的对象堆中,如果实例变量是基本类型的话,开辟相应的内存空间来存储相应类型的值,但是如果是引用类型的变量,保存的并不是对象本身,而是对象在对象堆上的地址,而什么时候在对象堆上开辟内存空间来保存这个对象,是要看哪时候new出这个对象;
创建对象的奇迹:创建对象分三个步骤:1.声明引用类型变量。2.创建对象;3.连接对象与引用;
构造函数:
构造函数没有返回类型;如果你没有写构造函数,编译器会帮我写构造函数;构造函数不会被继承;
使用构造函数来初始化对象;
父类以及继承与构造函数之间的关系
;
父类的构造函数在对象的生命中所扮演的角色;
当你new一个子类时,必定要触发构造函数链;
如果在子类的构造函数中,你没有写super();(调用父类的构造函数);编译器会帮你写;但是会调用父类无参构造函数;有参的构造函数需要自己手动的写;
在构造函数中 ,你也可以写this();来执行同一个类的另一个构造函数;但是在super()不能和 this();同时调用;
对象的生命周期;
如果对象生命周期要引用变量的生命舟曲而定,就要看变量到底会存活多久;
就会两种情况:局部变量;局部变量只会存活在声明该变量的方法中;当方法被执行完毕,从堆栈中弹出去之后,就会被销毁;
实例变量的寿命与对象相同,如果对象还活着,则实例变量也会是活的;
除非有对对象的引用,否则该对象一点意义也没有。
有三种方法可以释放对象的引用;
1.引用永久性的离开它的范围;
public class StackRef{ public void foof(){ barf(); } public void barf(){ Duck d = new Duck(); } }
只要barf()这个方法执行完毕,从方法的堆栈中弹出去后,d这个局部变量就会被销毁,所以引用变量消失,从而new出来的对象,也会在对象堆中消失了。
2.引用被赋值到其他的对象上;
public class ReRef{ Duck d = new Duck; public void go(){ d = new Duck(); } }
d是个实例变量,当在方法go中把它重新赋给新的对象;原来的那个对象就没有了引用变量来引用它了,所以就会被销毁了;
3.直接将引用设定为null;
public class ReRef{ Duck d = new Duck; public void go(){ d = null; } }
跟前一个例子相同的道理;
数字与静态;
静态方法:
一种不依靠实例变量也就不需要对象的行为;静态方法通过static来声明;
带有静态方法的含义;
静态的方法不能调用非静态的变量;
静态的方法有也不能调用非静态的方法;
静态方法无法看到实例变量的状态;
静态变量:
它的值对所有的实例来说都是相同的;
静态变量是在类加载时被初始化的,类会被加载是因为java虚拟机认为该类需要被加载了。所以就加载了这个类;第一次有人尝试创建这个类的实例;或者使用该类的静态方法和静态变量;
静态方法和静态变量有以下两个特点:静态变量会在该类在任何对象创建之前就进行了初始化。静态变量会在该类进行静态方法的执行完成了初始化。
包装对象:每一个基本数据类型都有个包装用的类,且这些包装类都在java.lang这个包中,所以你无须
import它们,每个包装类都很好辨别,
对象的相等:如果foo与bar两对象相等,则foo equals(bar)会返回true;且两者的hashCode()
也会返回相同的值;
引用到堆上同一个对象的两个引用是相等的,如果对两个引用调用hashCode()。就会得到相同的结果;
hashcode()默认的行为会返回每个对象特有的序号. 如果想要知道两个引用是否相等,可以使用== 来比较
变量上的字节组合,如果引用到相同的对象,字节组合也会一样。