一些基础
1.由于是面向对象的思想,在java中不再像cpp中一样,将其称之为成员函数和数据成员,相对应的叫法是对象的方法和属性。
2.java类中定义的属性叫成员变量,方法中定义的属性叫局部变量。
①java会自动给成员变量赋一个初始值(一般为0),但不会给局部变量赋初始值,编译时会提醒需要初始化。
②局部变量和成员变量同名时,局部变量具有更高的优先级。
3.在java中创建对象是需要new的,例如people是一个类:people xiaojie = new people();
cpp中 ,例如school是一个类:school *p = new school(参数)
或 school anewschool(参数)
都是可以的(不能school aschool = new school(参数)
)
注:类只有无参构造时cpp是不能用 school anewschool()
的,后面在使用anewschool的时候会报错“表达式必须包含类类型”,只能用school anewschool;
4.对象名.属性/对象名.方法调用,这个和cpp还是相同的。
5.cpp中的class一般也是没有public等访问控制符修饰的,但java有。且在类中java并不像cpp一样 public: protected: private: 这样分块来写 而是选择在么每个属性和方法前都加上访问控制符。
6.构造方法,即cpp中的构造函数,用于初始化对象。复习一下构造方法的知识:
构造方法无返回值类型且和类名相同。无参的构造方法可缺省,即系统会自动生成。但一旦自己写了构造方法,系统就不会补那个无参的构造了。构造方法可以有private、protected、public修饰,但不能由final、static、native、abstract等修饰。
构造时有些数字可能会存在不可能为负或者应该有一个范围的情况出现,此时可在构造方法中可以加if,如果数字超出范围,则提醒输入错误,并可自动给该属性赋一个合理的值并作提示 (当然正确时该属性的赋值要放在else里面 不然if执行之后不合理的值还是会进行赋值)(避免有参构造方法传值不安全)
7.修饰符顺序 <修饰符>[static][final]<变量类型><变量名>
8.方法重载的原则:方法名相同,参数不同(类型、个数、顺序只要有一项不同即可认为不同)。方法的返回类型和修饰符可以不同。 当然,调用方法要明确,不要出现两种方法都可以匹配的情况,这样会报错的。
static关键字
Java 中被 static 修饰的成员称为静态成员或类成员。它属于整个类所有,而不是某个对象所有,即被类的所有对象所共享(其实通俗一点说就是!一改就全改了!而不是各个实例化出来的对象会在同一变量保有不同的值)。静态成员可以使用类名直接访问,也可以使用对象名进行访问。当然,鉴于他作用的特殊性用类名直接访问较为多见。
类别 | 静态对象 | 非静态对象 |
---|---|---|
拥有属性 | 是类共同拥有的 | 是类各对象独立拥有的 |
内存分配 | 内存空间上是固定的 | 空间在各个附属类里面分配 |
分配顺序 | 先分配静态对象的空间 | 继而再对非静态对象分配空间 |
A,静态对象的数据在全局是唯一的,一改都改。如果你想要处理的东西是整个程序中唯一的,弄成静态是个好方法。 非静态的东西你修改以后只是修改了他自己的数据,但是不会影响其他同类对象的数据。
B,引用方便。直接用 类名.静态方法名 或者 类名.静态变量名就可引用并且直接可以修改其属性值,不用get和set方法。
与静态变量一样,我们也可以使用 static 修饰方法,称为静态方法或类方法。
A、 静态方法中可以直接调用同类中的静态成员,但不能直接调用非静态成员。如果希望在静态方法中调用非静态变量,可以通过创建类的对象,然后通过对象来访问非静态变量。
B、 在普通成员方法中,则可以直接访问同类的非静态变量和静态变量
C、 静态方法中不能直接调用非静态方法,需要通过对象来访问非静态方法。
待续:关于静态初始化块
封装
封装指的就是 对数据的保护(private) 通过getXXX和setXXX去调用
eclipse中自动生成 getter和setter方法:source->generate getter and setter
包:管理java文件 解决同名文件冲突问题
package 包名 必须放在java源程序第一行,包名间可以用”.”号隔开、
例如:highschool包中和college包中都有StudentNumber这个类 那么就用highschool.StudentNumber
和college.StudentNumber
来区分
使用包中的某个类 import college.StudentNumber
注:java中 包的规范命名是全小写字母拼写
利用* 例如 import com.college.*
可以加载该包下的所有文件
访问修饰符 :
private:本类可以调用 默认:本类和同一包中可以调用
protected:本类和同一包中和子类可以调用 public:啥时候都能调用
类的访问修饰符可以是public或缺省 ,类成员(属性和方法)的修饰符可以是以上四种。显然,类成员的可见性同时受类的可见性的约束。
this关键字代表当前对象 this.属性 this.方法 常用于封装对象属性
(为了区分相同的属性名和参数名)
pubilc void setNumber(int number)
{
this.number=number;
}
继承
java是单继承 也就是说一个类只有一个父类 和cpp不同
继承使用extends关键字:class 子类 extends 父类(cpp中: class 子类:访问控制符 父类)
可重写(覆盖)父类方法 调用方法时看引用的对象时父类还是子类
(只有当返回值类型 方法名 参数类型及个数都与父类继承的方法相同,才叫方法的重写 )
方法覆盖的原则:
1.子类的方法不能缩小其对应的父类方法的访问权限。
2.子类方法不能抛出比父类方法更多的异常
3.父类的静态方法不能被子类覆盖为非静态方法,反之亦然。
方法的覆盖只存在于子类和父类中,若在同一个类中,只能进行重载而不能覆盖。
初始化顺序:父类属性-父类构造方法-子类属性-子类构造方法
子类的构造过程中必须调用其父类的构造方法(也即会自动补上一个super();) 子类构造方法中若未显式调用父类的构造方法,则默认调用父类的无参构造方法(若父类没有,则编译出错。也即若父类只有有参构造而没有写无参构造,则必须显式调用)
注:若想显式调用父类构造方法,则必须放在构造方法的第一行
final修饰类 则该类不允许被继承
final修饰方法 则该方法不允许被覆盖(重写)
final修饰方法的参数 则该参数不希望被方法改变
final修饰基本类型变量 就是常量了
final修饰引用类型变量,该引用变量的值不能被改变,但其引用的对象的成员变量可以改变。
super关键字在对象的内部使用,可代表父类对象 用super.属性 super.方法()来调用父类的属性和方法。如果super未在直接父类查找到匹配成员,则逐层向上到祖先类去寻找。this访问成员先在本类中查找,若未找到,则由父类逐层向上寻找。(均符合最近匹配原则)
Object类是java中所有类的父类。Object类中有一些比较重要的方法。
1.toString()方法
例如:people是一个类
people yogi = new people();
System.out.println(yogi);
输出结果会是yogi对象在内存中的地址,前面加上people类名和包名
如果想要这样写且直接输出某个yogi的属性 比如name 则覆写toString方法
如:
public String toString()
{
return "yogi's name:"+name;
}
当然这样的覆写 eclipse也可以完成 source->generate toString
2.equals()方法
比较对象的引用是否指向同一块内存地址
people yogi = new people();
这时的yogi并不是我们创建的对象 其实仅仅是对象在内存中的地址 通过操作yogi 来达到操作对象的目的 所以 yogi就是对象的引用(引用了内存当中的一块地址)
我们可以把比较是否同一个 重写成 比较是否值相等(但内存地址不同)
equals()方法的用法:
people1.equals(people2) 若相同 则结果为true 否则为false
也不用自己写 eclipse中可以source->Generate hashCode() and equals()(比较的属性可选 也就是说 可以认为如果某属性值相等 则相等)
(前面的哈希方法如果用不上就删了吧)
实现的话就是用if来判断各个属性值是否相等
//返回值是布尔类型
public boolean equals(Object obj)
{
//比较地址是否相同 若地址相同则对象一定相同
if(this == obj)
return true;
//如果另一个对象空值 则一定不等
if(obj == null)
return false;
//getClass()可以得到类对象(当使用new时 产生的叫类的对象 而用getClass产生的是类对象)类对象描述的是一个类的代码信息 比如说类中的有些什么属性、方法和变量名,而类的对象更关注属性值(数据)的信息 经常用类对象来判断类的类型 以下判断类的类型是否相同 若类型不同 则一定不等
if(getClass() != obj.getClass())
return false;
//将传进来的对象转换为people类型(类型相同才能转 而且只有类型相同才能比较属性值是否一样)
people other = (people) obj;
//比较值是否相等(这是只需要比较name一个属性时的情况)
if(name != other.name)
return false;
return true;
}
有时候看似没有必要的继承其实也是有好处的,比如说:可以直接用父类类型开数组 那么数组元素就可以是各种子类类型了。
多态
多态:①引用多态 ②方法多态 (继承是多态实现的基础)
引用多态 父类引用可以指向其子类对象
animal obj = new dog();
方法多态是说创建子类对象的时候调用的是子类的方法(当然子类独有而父类没有的方法时不允许用父类的引用创建的对象调用的)
引用类型转换
子类转向父类是隐式的、自动的转换(其实在上面引用多态的时候就有一个向上类型的转换),而父类转子类就是强制类型转换了。不难理解,论方法和属性,父类含于子类。
instanceof运算符可以解决引用对象的类型,避免类型转换的安全性问题
例如:关于animal和dog
dog ww = new dog();
animal ani = ww;(自动转换)
dog w2 = ani;
←这样就是不行的 虽然ani的其实就和ww是一样的 但是 还是animal类型 还是要写成dog w2 = (dog) ani;
但是这样也会有问题 因为 比如说再有一个类继承了animal 叫cat
那cat miao = (cat) ani
就会出问题啦 无法将引用类型进行转换
应该在上面这条语句前加判断 if(ani instanceof cat)
if括号中的语句会返回布尔值
方法多态实际指的就是方法重载和方法覆盖
方法重载又称为静态多态,因为其执行效果在编译时就被固定下来了。
方法覆盖又称动态多态,因为程序运行时可以通过替换对象来动态地改变运行效果。
抽象类 前面使用abstract关键字修饰(cpp中为virtual)
抽象类不能被实例化,只能被继承,且关注子类必须有哪些方法
abstract定义抽象方法 只需声明不需实现(写完()之后直接以;结束 不需要大括号)
抽象类中不一定要有抽象方法,但含有抽象方法的类一定要定义为抽象类。抽象类的子类可以不实现其父类的抽象方法(也即子类依旧是抽象类)
类不能同时用final和abstract修饰,方法不能同时用static和abstract修饰
接口
接口不使用class关键字 而使用interface关键字
接口由公开的静态方法和常量组成
语法:
[修饰符] interface 接口名 [extends 副接口1,副接口2,…](可多继承)
{
零到多个常量定义…
零到多个抽象方法定义…
}
接口就是用来被继承、被实现的,所以一般用public修饰
接口中的属性是常量,即使定义时不添加public static final修饰符,系统也会自动加上 方法也是一样 就算不添加public abstract修饰 也会自动加上
一个类可以实现一个或多个接口(弥补只能继承一个父类的不灵活)
继承父类实现接口:(extends关键字一定要在implements关键字之前)
[修饰符] class 类名 extends 父类 implements 接口1,接口2…
{
}
一般给接口命名时在前面加一个I(大写的i),以示和class不同。
接口名 对象名 = new 类名();和类名 对象名 = new 类名();起到的作用是一样的
接口在使用过程中,还经常与匿名内部类配合使用(匿名内部类就是没有名字的内部类,多关注于功能的实现而不是内部类的名称)
例如Iname yogi = new person(){};
(分号结束哦)括号里面就直接写在接口里声明了的一定要写的方法。
在使用这种匿名内部类的方式时也可以直接new,也就是new Iname(){}.方法名();