一、类与对象
1.面向对象的概念
2.类
(1)类的定义
class 类名 {
//可编写0至n个属性
数据类型 变量名1;
数据类型 变量名2;
//可编写0至n个方法(函数)
修饰符 返回值类型 方法名(参数){
执行语句;
}
}
例 定义一个汽车类
小汽车 {
颜色;
轮胎个数;
运行() { }
}
public class Car {
String color;
int number;
void run() {
System.out.println(color + ":" + number);
}
}
(2)类的修饰符
①访问控制符public
公共类public:公共类,说明这是一个公共类,可以被其它任何类引用和调用。
不写访问控制符,表示类只能被本包的其他类访问。
②抽象说明符abstract
抽象类abstract,放在访问控制符后边,表示这个类是抽象类,抽象类不能直接产生实例化一个对象,他只能被继承。
抽象类就是没有具体实例化对象的类。
特征:至少含有一个抽象方法
优点:抽象类是所有它的子类的公共属性的集合,可以利用充分利用这些公共属性提高程序开发和维护的效率。
③最终类说明符final
最终类final,以final作为关键字,如果有的话,应该放在访问控制符后面,表示这个类是个最终类,最终类不能被继承,不能再派生出其它子类。
例如,Java.lang语言核心包中定义了String(初始化时长度固定)和StringBuffer(初始化后长度可变)两个来封装对字符串的各种操作,它们都是final类,不能被其它类继承。
(3)类的属性(成员)的修饰符
①访问控制符4个:default private protected public
default(默认)——也可以不写,成员可以被本包的其他类访问
private——私有,成员只能被本类使用
protected——被保护,成员可被本包其他类访问,也可以被声明它的类和派生的子类访问。
public——公共,成员可被所有的类访问
②静态修饰符static
特点:它们是类的属性,而不属于任何一个类的对象。即:对于该类的任何一个对象,静态属性是一个公共的存储单元,任何一个类的对象访问它时,得到的都是相同的数值。同理,任何一个类的对象去修改它时,也都是对同一个内存单元进行操作。
static修饰的变量 —类变量
static修饰的函数— 类函数
d1.a->d2.a-> class.a
1.有static修饰的成员变量,被所有的对象互通使用(区别于对象间的独立使用)。
2.有static修饰的成员变量,可以使用 类名.成员变量。
③最终说明符final
用final声明的变量就是最终变量,即常量,其值不可改变。
(4)类的成员方法的修饰符
访问控制符4个
静态修饰符static
抽象方法修饰符abstract
最终方法final
同步修饰符synchronous
本地修饰符native
(5)方法(函数)
(一)函数概念:
函数是一块代码块,接受零个或多个参数,做一件事情,并返回零个或一个值。
可以先想想成数学中的函数:y=f(x)
(二)函数的定义
(三)函数的调用:
函数名()
>例:求a~b之间的素数,并求和
public class Hello {
//判断素数的函数
public static boolean isPrime(int i)
{
boolean result = true;
for(int k =2;k<i;k++)
{
if(i%k==0)
{
result= false;
}
}
return result;
}
public static void main(String[] args) {
int sum=0;
int cnt=0;
Scanner in =new Scanner(System.in);
System.out.println("请输入a:");
int a =in.nextInt();
System.out.println("请输入b:");
int b =in.nextInt();
for(int i = a;i<b;i++)
{
if(isPrime(i))
{
sum+=i;
cnt++;
}
}
System.out.println(a+"和"+b+"之间有"+cnt+"个素数,他们的和为:"+sum);
System.out.print("分别为:");
for(int i = a;i<b;i++)
{
if(isPrime(i))
{
System.out.print(i+" ");
}
}
}
}
(四)函数与变量 类型的匹配:
大变小:自动转换
小变大:强制转换
例如:函数期望的参数类型是double,而你输入的是int,会自动将int->double,不会降低精度。
反之必须进行强制类型转换。
也就是说,类型的变化依据的是函数期望的参数类型(初始定义的类型)
3.对象
(1)创建对象的步骤:
创建一个对象:
类名 对象名 = new 类名(参数);
此过程需要三步:声明引用变量、实例化、初始化对象实例:
①声明Declaration :等号左边 将变量名称与对象类型关联—>变量声明。
②实例化Instantiating :new运算符实例化一个类对象(创建一个对象),然后给这个对象分配内存并返回一个指向该内存的引用。
③初始化Initialization:new运算符随后调用构造函数,由构造函数初始化新创建的对象。
(2)创建对象的格式:
①格式一:声明并实例化对象
类名称 对象名称 = new 类名称 () ;
Person per = new Person() ;// 声明并实例化对象
②格式二:先声明对象,然后实例化对象:
类名称 对象名称 = null ;
对象名称 = new 类名称 () ;
Person per = null;//声明对象
per = new Person() ;//实例化对象
(3)New 的作用:
①实例化一个类对象(创建一个对象)
new运算符实例化一个类对象(创建一个对象),然后给这个对象分配内存并返回一个指向该内存的引用。
“实例化一个类的对象”的意思就是“创建对象”。创建对象时,你正在创造一个类的“实例”,因而“实例化”一个类的对象。
②调用构造方法:
实例化对象之后,new运算符也调用了对象的构造函数,由构造函数进行初始化。
总结:
Java关键字new是一个运算符。与+、-、*、/等运算符具有相同或类似的优先级。
创建一个Java对象需要三部:声明引用变量、实例化、初始化对象实例。
**实例化**:new就是“创建一个Java对象”-----分配内存并返回指向该内存的引用。
**初始化**:就是new调用构造方法,然后构造方法对类的实例数据赋初值。
原文链接:https://blog.csdn.net/u013851082/article/details/56675837
二、构造方法
new(创建)一个对象时,实例化完成之后,new会自动调用该类中构造函数,然后,构造函数将对象的成员变量初始化。
new一个对象时,new调用构造函数,例如Hello hello = new Hello();这时调用的是Hello的无参数构造方法;Hello hello = new Hello(“hi”);这个是调用Hello有参数构造方法。
在JAVA中如果不写构造方法的话,会默认加上一个无参数的构造方法,但是如果已经有了一个有参数的构造方法,那么无参数的构造方法就不会默认被加上。如果Hello类中已经有了一个有参数的构造方法,这时再使用 Hello hello = new Hello();来创建对象的时候就会出错,这就是为什么书上要强调写了有参数的构造方法就最好加一个无参数的构造方法。
原文链接:https://blog.csdn.net/zw1996/article/details/52878270
1.构造方法的定义声明
所谓构造方法,就是在构造对象是自动调用的方法
构造方法的方法名必须与类名一样。
构造方法没有返回类型,也不能定义为void,在方法名前面不声明方法类型。
构造方法的作用是完成对象的初始化工作,他能够把定义对象时的参数传递给对象的域。
构造方法不能由编程人员调用,而要系统调用。
构造方法可以**重载**,以参数的个数,类型,或排序顺序区分。
例:
class Fu
{
public Fu(){} //无参的公有构造方法
public Fu(int i){} //参数类型为int的公有构造方法
......
}
public class Demo extends Fu
{
public Demo(){} //无参的公有构造方法
public Demo(int i){} //参数类型为int的公有构造方法
public Demo(int i,double d){} //参数类型为int和double的公有构造方法
...
}
2.构造方法的使用
java中构造方法的使用有两个地方:
①跟在关键字new后面 类名(),()内根据实际加上实参。
②跟在关键字super()或this(),小括号内根据实际添加实参
下面进行举例。
例1:
Demo demo = new Demo();
//这里是调用的是一个无参的构造方法,必须声明在方法中,最好声明在主方法
上面构造方法的参数根据实际添加实参,jvm根据构造方法的参数不同而选择加载不同的构造方法;
例2:
public Demo(){
this(2); //这里调用参数为int类型的**本类的构造方法**
}
例3:
public Demo(){
super(1); //调用参数为int类型的父类的构造方法
}
注意:
例2和例3中this或super调用构造方法只能出现在构造方法中,而且必须出现在第一行,所以一个构造方法中第一行只能为this或super调用构造方法,两者不能同时调用构造方法出现,而且注意this或super调用构造方法时,要留构造方法出口,意思就是最后调用的构造方法中没有再调用别的构造方法!
创建子类对象会调用父类构造方法但不会创建父类对象,只是调用父类构造方法初始化父类成员属性;
在子类中只实例化了一个子类对象。从输出结果上看,程序并不是一开始就运行自己的构造方法,而是先运行其父类的默认构造方法。
注意:程序自动调用其父类的默认构造方法。
原文链接:https://blog.csdn.net/u010785140/article/details/46963457
2.构造方法的重载
构造方法可以重载,以参数的个数,类型,或排序顺序区分。
一个类可以有多个构造方法,只要他们的参数不同。
创建对象时给出不同的参数值,就会自动调用对应的构造函数
通过this()还可以调用其他的构造函数
一个类里的同名但参数表不同的函数组成了重载关系
三、this与super
1.this的作用
作用一:引用成员变量
this.变量 :在一个对象内部代表成员变量。
在一个对象中,含有成员变量和成员方法,其中成员方法中含有局部变量(本地变量),当局部变量和成员变量重名时,让 this.变量名 来表示对象中的成员变量。
this引用的成员变量,只在本对象内使用。
Public Class Number {
int a= 5; //定义一个成员变量a
private void A (int a) { //定义一个局部变量 a
this.a=a; //将局部变量的值传递给成员变量
}
syso
//对象1调用了函数A,所以对象1的成员变量a变为了0
Number dx1 = new Number();
dx1.A(0);
//对象2没有调用函数A,对象2的成员变量a还是5
Number dx2 = new Number();
}
除此之外,对象内的各个方法之间的局部变量之间是没有任何联系的,不可以相互调用。而方法可以直接调用成员变量,当然,在局部变量和成员变量重名时最好用this.来表示成员变量。
//定义类
public class Number {
//定义成员变量a
int a= 5;
//定义成员方法1
void f1(int a ) {
this.a=a;//正确。将成员变量a赋值,重名用this
}
//定义成员方法2
void f2(int b) {
a=b;//正确。将成员变量a赋值
}
//定义成员方法3
void f3(int c) {
b=c;//错误。方法之间的变量不能相互调用
}
具体案例:
//定义一个类
public class VendingMachine {
int a= 5;//定义一个成员变量
//函数1的作用:修改成员变量
public void out1 (int a) { //定义一个局部变量(本地变量)
this.a=a; //将局部变量的值赋给成员变量
System.out.println(a); //输出局部变量
}
//函数2的作用:输成员地变量
public void out2() {
System.out.println(a); //输出成员变量
}
public static void main(String[] args) {
//创建对象1
VendingMachine vm1 = new VendingMachine();
vm1.out1(0);// 将成员变量改为0
vm1.out2();// 输出成员变量的值为0
//由于out1时,将次对象的成员变量a被局部变量赋值为0,所以out2时,输出的成员变量变成0
//但是,this.指的只是本对象的成员变量,而非类的成员变量。
//创建对象2
VendingMachine vm2= new VendingMachine();
vm2.out2();// 输出成员变量的值为5
//没有执行out1,没有将成员变量改变,还是5
//**由对象1和对象2比较可知:
//**this.代表的是本对象的成员变量,而不是类中的成员变量,各个对象之间是没有联系的。**
}
}
作用二:调用类的构造方法(构造函数)
public class Student { //定义一个类,类的名字为student。
public Student() { //定义一个方法,名字与类相同故为构造方法
this(“Hello!”);//调用了下边的构造函数
}
public Student(String name) { //定义一个带形式参数的构造方法
}
}
作用三:返回对象的值
2.super的作用
调用父类的成员或方法
四、封装
1.封装的概念
将类的某些信息隐藏在类的内部,不允许外部程序直接访问,而是通过该类提供的方法来对隐藏的信息进行操作和访问。
2.好处:
(1)只能通过规定的方法访问数据
(2)隐藏类的实例细节,方便修改和实现。
3.封装的实现步骤
(1)修改属性的可见性设为(private)
(2)创建getter/setter方法(用于属性的读写)(通过这两种方法对数据进行获取和设定,对象通过调用这两种发方法实现对数据的读写)
(3)在getter/setter方法中加入属性控制语句(对属性值的合法性进行判断)
案例:
class Book{
//定义两个封装属性变量,正能本类才能访问
private String title;
private double price;
//定义getter方法,用于获取数据
public String getTitle() {
return title;
}
//定义setter方法,用于写入数据
public void setTitle(String title) {
this.title = title;
}
//定义getter方法,用于获取数据
public double getPrice() {
return price;
}
//定义setter方法,用于写入数据
public void setPrice(double price) {
this.price = price;
}
public void getInfo(){
System.out.println("图书的名称:"+title+" 图书的价格:"+price);
}
}
public class TestDemo {
public static void main(String args[]) {
Book book = new Book();
book.setTitle("Java开发");
book.setPrice(-89.9);
book.getInfo();
}
}
运行结果;
图书的名称:Java开发 图书的价格:-89.9
开发建议:以后在定义类的时候,所有的属性都要编写private封装,封装之后的属性如果需要被外部操作,则编写setter、getter。
五、继承
继承是java面向对象编程技术的一块基石,因为它允许创建分等级层次的类。
继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为
2.类的继承格式
class 父类 {
}
class 子类 extend 父类{
}
3.继承的目的
为了降低代码的冗余度
4.继承的类型
Java支持多重继承,但不支持多继承
①单继承
public class A {
…
}
public class B entends A {
…
}
②多重继承
public class A{…}
public class B extends A {
…
}
public class C extends B {
…
}
③不同类继承同一个类
public class A {…}
public class B extends A {…}
public class C extends A {…}
5.java继承特性
- 子类拥有父类非 private 的属性、方法
- 子类可以拥有自己的属性和方法,即子类可以对父类进行扩展。
- 子类可以用自己的方式实现父类的方法
- Java的继承单继承,但是可以多重继承,单继承就是一个子类只能继承一个父类,多重继承如上所示。
- 提高了代码的耦合度,同时缺点也就随机而来,耦合度越高,代码联系越紧密,代码的独立性就越差。
6.继承关键字
继承关键字可以使用extends和implements,并且所有类都继承于java.lang.Object,当一个类没有继承关键字,默认继承在object祖先类。(object类在java.lang包中,不需要import—<导入包的关键字>。)
(1)extends关键字
在Java中,类的继承是单一继承,也就是说,一个子类只能拥有一个父类,所以extends只能继承一个类。
(2)implements关键字
使用 implements关键字可以变相的使java具有多继承的特性,使用范围为类继承接口的情况,可以同时继承多个接口(接口跟接口之间采用逗号分隔)。
7.super与this关键字在继承中的应用
-
super关键字:可以通过super关键字来实现对父类成员的访问,用来引用当前对象的父类。
-
this关键字:调用子类的方法(本类内的方法)
由于继承关系,子类将拥有所有父类的方法,也就是说,this相当于没用,但要考虑方法重名时的覆盖
例子:
class Fulei {
void f1() {//父类方法
System.out.println("调用父类 方法");
}
void f3() {//父类方法
System.out.println("调用父类 方法3");
}
}
class Zilei extends Fulei {
void f1() {//子类方法(与父类方法重名了)
System.out.println("调用子类 方法1");
}
void f2() {
System.out.println("调用子类 方法2");
}
void getResult() {
f1(); // 由于发生覆盖,自动执行子类方法
super.f1(); // super 调用父类方法
f2(); // this 调用子类的方法,继承后父类的方法变成了子类的方法,所以带不带this都行
this.f3();//
}
}
public class test {
public static void main(String[] args) {
Fulei f = new Fulei();//创建一个父类对象 f
Zilei z = new Zilei();//创建一个子类对象 z
f.f1();
z.getResult();
}
}
结果:
调用父类 方法
调用子类 方法1
调用父类 方法
调用子类 方法2
调用父类 方法3
8.方法的覆盖
如果子类中的一个方法与父类中的方法有相同的方法名,并具有相同数量和类型的参数列表,则称子类中的方法覆盖了父类中的方法。通过子类引用覆盖方法时,总是引用子类定义的方法,而父类中定义的方法被隐藏。 (案例在上方)
六、多态
多态:
Animal animal= new Animal();
Dog dog = new Dog ();
Cat cat =new cat();
将子类的对象赋给父类是可以的。(拿一个子类对象,当做父类对象来用)
Animal a = new Dog();
Animal b = new Cat();
将父类的对象是错误的,
Cat c = new Animal ();
造型 :把对象当成此类型,但对象的实质类型不变
(造型区别于类型转换,类型转换是将主数据类型的变量转换,是实质上的转换)
向下造型
c= (cat)a;可以,但编译错误。
c =(cat)b;正确
向上造型
系统默认的,拿一个子类对象,当做父类对象来用。
动态绑定
用.运算符调用方法时,多态所调用的方法是实际对象的方法。
七、接口
1.什么是接口
官方解释:Java接口是一系列方法的声明,是一些方法特征的集合,一个接口只有方法的特征没有方法的实现,因此这些方法可以在不同的地方被不同的类实现,而这些实现可以具有不同的行为(功能)。
我的解释:接口可以理解为一种特殊的类,里面全部是由全局常量和公共的抽象方法所组成(即只有方法标识符,而没有方法体)。接口是解决Java无法使用多继承的一种手段,但是接口在实际中更多的作用是制定标准的。或者我们可以直接把接口理解为100%的抽象类,即接口中的方法必须全部是抽象方法。(JDK1.8之前可以这样理解)
接口就是描述了一种能力,接口的作用就是告诉类,你要实现我这种接口代表的功能,你就必须实现某些方法,我才能承认你确实拥有该接口代表的某种能力。
2.接口的使用:
(1)第一步,定义一个接口,格式如下:
[访问说明符] interface 接口名称 {
// 声明变量 静态全局常量 public static final
// 抽象方法 必须是抽象的,没有具体实现 public abstract
}
说明:
a.接口里的方法必须是public abstract(默认public abstract,这两个修饰符可不写);
b.接口里的变量默认为public static final (必须是public);而且没有{}
c.接口里只能放方法的声明,而不能定义。
(2)第二步,定义一个类来实现这个接口,格式如下:
在类声明时,利用implements子句来表示一个类使用了某个接口,也就是说实现了某个接口,格式是:
[访问说明符] class 类名 implements 接口名称1,接口名称2,....{
//接口的所有方法的实现(具体方法)
//类的属性
//类的方法
}
说明:
a.一个类可以实现多个接口,这些接口放在implements关键字后面,用半角逗号隔开;
b.实现接口的类必须实现接口里所有的方法
2.接口的继承
接口可以多继承,类只能单继承。格式如下:
[可见度] interface 接口名称 [extends 其他的接口名, 其他的接口名, 其他的接口名……] {
// 声明变量
// 抽象方法
}
3.为什么要用接口?
1.接口被用来描述一种抽象。
2.因为Java不像C++一样支持多继承,所以Java可以通过实现接口来弥补这个局限。
3.接口也被用来实现解耦。
4.接口被用来实现抽象,而抽象类也被用来实现抽象,为什么一定要用接口呢?接口和抽象类之间又5.有什么区别呢?原因是抽象类内部可能包含非final的变量,但是在接口中存在的变量一定是final,public,static的。
通俗的将,我设置了一个接口,里面的功能还没有实现,
要想实现它,我需要用其他的一个类去实现它。
接口就相当于一个功能的名字
接下来用一个例子来说明为什么要用接口:
// 一个简单的接口
interface in1
{
// 定义一个静态全局常量
final int a = 10;
// 定义一个抽象方法
void display();
}
// 定义一个类去实现这个接口
class testClass implements in1
{
//这个类实现了接口的功能
public void display()
{
System.out.println("Geek");
}
其中testClass类实现了我们上面刚才定义的 in1 这个接口既然你要实现接口,也就是实现接口代表的一种能力,那么你就必须去实现接口给你规定的方法,只有把接口给你规定的抽象方法都给实现了,才承认你这个类实现了这个接口,实现了这个接口代表的某种功能。上图实现了接口中规定的display()方法。
写一个测试类,用来测试一下我们刚才实现的这个接口:
因为testclass类的对象t实现了接口规定的display方法,那么自然而然就可以调用display()方法咯。
// 运行代码
public static void main (String[] args)
{
testClass t = new testClass();
t.display();
System.out.println(a);
}
}
运行结果:
Geek
10
例:
class MyClass implements Range{
… }
//定义一个接口
interface TestInterface {
String getName();
}
//定义一个类TestClass 类,来实现TestInerface接口
class TestClass implements TestInterface {
public String getName() {//此类实现了接口的抽象方法
return "正在调用类TestClass,此类实现了接口 TestInterface"; }
}
//定义一个InterfaceTest类
public class InterfaceTest {
public void printName(TestInterface t) { //
System.out.println(t.getName());
}
public static void main(String[] args) {
//定义一个对象_testClass
TestClass _testClass = new TestClass();
//定义一个对象_test
InterfaceTest _test = new InterfaceTest();
_test.printName(_testClass);
}
}