Java中两种编程思想
面向过程POP:
是一种基本的编程思想,按照流程一步一步实现。 侧重于分析完成事情的过程
面向对象OOP:
是当前主流的编程思想,创建解决问题的对象,并且赋予对象行为和特征。
将所有的事情交给对应的对象完成,侧重于创建解决问题的对象
对象和类
类class
将具有相同属性和行为的对象放在一起称为一类。
属性是描述对象的特征,通过定义变量表现属性
行为是描述对象的动作,通过定义方法表现行为
定义类
语法:[修饰符] class 类名{//属性//行为}
例:
public class Person{
//定义属性
String name;//名字
int age;//年龄
//定义行为
void eat(){//吃饭
System.out.println(name+"在吃饭");
}
}
对象Object
概念:对象是类的一个具体实例,是类的具体表现
语法:类名 对象名= new 构造方法([参数]);
调用类中的非私有的属性和行为: 对象名.属性或者对象名.方法名
以上一个类为调用例子:
public static void main(String[] args){
Person p = new Person();
p.name="张三";
p.age=20;
System.out.println(p.name+"今年"+p.age+"岁了");
}
成员变量、局部变量、静态常量
成员变量:定义在类中的变量称为成员变量,有默认值,通过对象访问。
局部变量:定义在方法中的变量称为局部变量,没有默认值。在方法中赋值后才能使用。
静态常量:特殊的成员变量,用final static修饰,有默认值,通过类名访问。
public class Animal{
String type;//成员变量
final static String NAME="旺旺";//静态常量
void info(){
String color="灰色";//局部变量
}
}
方法
概念:一段独立的代码,能够完成某个功能,可以反复被调用,能够减少重复的代码。
方法的调用
1.通过对象调用:对象名.方法名
//创建一个Random类的对象rd
Random rd = new Random();
//生成[0,10)区间的随机数
double num = rd.nextInt(10);
2.通过类名调用:类名.方法名
double res = Math.pow(3,2);
3.直接调用:方法名
public void A(){}
public void B(){
` A();
}
自定义方法
语法:修饰符 返回值 方法名([参数类型 参数]){方法体}
1.无参无返回值方法
2.无参有返回值方法
3.有参无返回值方法
4.有参有返回值方法
public class User { //无参无返回值 public void fun(){ System.out.println("无参无返回值"); } //有参无返回值 public void fun2(int id){ System.out.println("有参无返回值"); } //无参有返回值 public boolean fun3(){ System.out.println("无参有返回值"); return true; } //有参有返回值 public boolean fun4(int id){ System.out.println("有参有返回值"); return true; } }
//调用
public class Main { public static void main(String[] args) { User user = new User(); //调用无参无返回值 user.fun(); //调用有参有返回值 user.fun2(1); //调用无参有返回值 user.fun3(); //调用有参有返回值 user.fun4(1); } }
注意:
1.无返回值的方法,返回值部分要写成void
2.有返回值的方法,方法体中要写上return,并且在return后写上对应返回值类型的数据
3.有返回值的方法在调用时,需要接受返回的数据才能使用该数据
4.方法定义时的参数称为形式参数,简称为形参,方法在方法体中使用,方法调用时传递的值称为实际参数,简称为实参,需要保证满足形参的数据类型即可,与形参无关。
5.没有返回值的方法体中,也可以使用return关键字,但不能有值,只要出现return关键字,后续的代码不再执行
6.方法中有static关键字,可以使用类名.方法名调用
构造方法
语法:修饰符 方法名()
构造方法是一个特殊的方法,方法名必须和类名一致,没有返回值,每个类定义时都会生成一个隐藏的无参构造方法
作用:构造方法通常用于初始化成员变量
特点:
1.构造方法没有返回值部分,方法名必须和类名一致
2.每个类定义时候会生成一个隐藏的无参构造方法,没有方法体,用于创建无参数的对象
3.书写有参数的构造方法的同时默认生成的无参构造方法就会失效,需要重新书写。
4.只能通过new关键字创建对象时会自动调用,不能通过"."访问
5.构造方法可以限制创建对象的参数,所有的构造方法通常用于初始化成员变量。
访问修饰符
访问修饰符可以限制某个类、属性或者方法的访问权限
访问修饰符 | 含义 | 可以修饰 |
---|---|---|
public | 公共的 | 类、属性、方法 |
protected | 受保护的 | 方法、属性 |
不写(default) | 默认的 | 类、属性、方法 |
private | 私有的 | 属性、方法 |
访问权限表
同一个类 | 不同包中的子类 | 不同包中的非子类 | ||
public | √ | √ | √ | √ |
protected | √ | √ | √ | × |
不写(default) | √ | √ | × | × |
private | √ | × | × | × |
面向对象三大特性---封装、继承、多态
封装:
使用private关键字对类中的属性进行修饰
好处:能够防止其他的类对属性进行访问,可以保护关键属性,还能够隐藏类内部的实现细节
如果想要对私有属性进行读取或赋值,需要提供一组setter/getter方法
封装的步骤
1.给类中的属性全部添加private访问修饰符
2.给类中的每个私有属性添加getter方法,读取属性值
3.给类中的每个私有属性添加setter方法,给属性赋值
如:
public class User { private String name;//封装属性 public String getName() {//getter方法 return name; } public void setName(String name) {//setter方法 this.name = name; } }
//调用
public class Main { public static void main(String[] args) { User user = new User(); user.setName("张三"); System.out.println(user.getName()); } }
继承
使用extends关键字修饰的两个类
语法:class 类A extends 类B
public class Father {//父类
public void buy() {
System.out.println("父亲看见喜欢的东西就买");
}
}
public class Son extends Father {//子类
public void buy() {
System.out.println("儿子看见喜欢的东西就买");
}
}
继承的特点
1.如果多个类中有相同或相似的代码可以提出来放在一个公共类中,称为父类,那些类称为子类,子类继承父类,能够减少子类中重复的代码。
2.子类对象可以访问父类中非私有的属性和方法
3.子类可以将父类中的方法进行拓展或者覆盖,称为方法重写。重写方法后调用子类的对象,会执行重写后的方法内容
4.Java是单继承,一个子类只能有一个父类,一个父类可以有多个子类
5.Java可以多重继承,类A可以继承类B,类B可以继承类C,这是类A既是类B的子类,也是类C的子类,可以访问类B和类C 中非私有的属性和方法。
6.在创建子类对象时,会先执行父类中的构造方法
7.所有类的父类都是Object,但是没有用extends进行继承
在继承关系中,如果子类和父类都没有写出任何的构造方法,子类有一个隐藏的午餐构造方法,会自动调用父类中无参构造方法
public class Father{
//默认会有
/ /public Father(){}
}
public class Son extends Father{
//默认会有
/*public Son(){
super();*/
}
}
父类中没有无参构造方法,子类中必须调用父类中对用的构造方法
public class Father{
private String name;
//定义了一个有参构造方法,默认的无参构造方法就会失效
public Father(String name){
this.name =name;
}
}
public class Son extends Father{
public Son(String name){
//这里必须调用父类中的构造方法,否则无法通过编译
super(name);
}
}
方法重写Override
子类继承父类后,能够对父类中的非私有方法进行重写
必须有子类继承父类才能够重写方法
要求:
1.方法名、返回值、参数列表必须与父类一致
2.访问权限不能比父类更严格(访问修饰符的范围要大于等于父类的访问修饰符权限)
3.不能够抛出比父类更大的异常
方法重载Overload
如果一个类中多个方法名相同,参数列表不同时,将这些方法称为重载。最典型的重载方法是构造方法。(同名不同参)
方法重载必须写在同一个类中,某个方法在不同的条件下执行不同的内容
要求:
1.在同一个类中并且方法名相同
2.参数列表不同,包括数据类型和数量
3.与返回值无关
this和super关键字
都可以当作构造方法和对象使用。
当作对象:this表示当前类的对象,super表示当前类父类的对象,只能用在非静态方法中。
当作构造方法:this()表示当前类的无参构造方法,如果带参数就表示对应参数的构造方法
super()表示当前类父类的无参构造方法,如果带参数就表示对应参数的构造方法。
this()和super()只能用在构造方法中的第一行
final关键字
修饰属性
当final修饰属性时,该属性的值就不能改变
语法:final 数据类型 常量名;
例如: final NUM = 123; final PI = 3,14;
修饰方法
当final修饰方法,该方法不能更改,同时也不能重写
public class Father{
public final void fun(){
}
}
public class Son extends Father{
//会报错,提示该方法不能被重写
public void fun(){
}
}
修饰类
当final修饰类时,该类不能够被继承
public final class Father{
}
//会报错,提示该Father类不能被继承
public class Son extends Father{
}
Object类
object是所有类的父类,但没有用extends体现出来,有许多的方法可以让子类进行重写
常用方法 | 返回值 | 作用 |
---|---|---|
toString() | String | 在输出某个对象时,会默认调用该方法。该方法默认的输出模式:"包名.类名@十六进制的哈希码"。通常用于重写后输出对象的属性 |
hashCode() | int | 得到某个对象的哈希码。哈希码可以理解为对象内存地址通过一种算法转换得到的一个特定值。 |
getClass() | Class | 得到某个对象的所在类。默认输出"class 包名.类名" |
equals(Object obj) | boolean | 判断两个对象是否相同。Object中默认用==比较判断,通常需要对equals()进行重写 |
notify() | void | 唤醒某个线程 |
notifyAll() | void | 唤醒所有的线程 |
wait(long time) | void | 让线程休眠,直到被唤醒 |
finallize() | void | 当某个对象被GC垃圾回收机制回收前执行的代码 |
向上转型
子类对象转换成父类对象的过程称为向上转型(自动转换)
Person p = new Person();
//可以直接将子类对象保存到父类变量中
object obj = p;
向下转型
父类对象转换成子类对象的过程,称为向下转型,也称为强制转换
语法:要转换的对象前添加"目标类型"
//一个Object类型的对象
object obj = new Object();
//默认无法将父类对象保存到子类变量中,需要经过向下转型
Person p = (Person) obj;
多态:
概念:子类的对象指向父类的变量(子类对象使用父类的变量接收:向上转型)
多态通常用于定义方法时,形参为一个父类或接口类型变量,实参可以为子类对象
无法通过父类变量调用子类独有的方法,如果调用重写了父类的方法时,执行重写后的代码
public class Father{
}
public class Son extends Father{
}
public class Main{
public static void main(String[] args){
Son son = new Son();
//这就是多态的体现
//子类的对象,可以使用父类的变量保存
Father father = new Son();
}
}
多态的实现条件
1.需要有继承关系
2.子类需要重写父类中的方法
3.子类对象使用父类的变量接收
应用:当某个方法的参数为父类变量时,可以传递不同的子类对象,可以执行不同的方法
抽象abstract
修饰类:被修饰的类称为抽象类
语法:访问修饰符 abstract class 类名{}
如果一个类中有抽象方法,那么这个类一定是抽象类
注意:
1.抽象类不能被实例化,无法创建对象
2.抽象类中有构造方法,在创建子类对象时会自动调用执行
3.抽象类中可以有抽象方法,也可以有非抽象方法
4.抽象类的子类要么继续为抽象类,要么重写抽象类中的所有方法
修饰方法:
语法:访问修饰符 abstract 返回值类型 方法名(参数类型 形参名称){}
public abstract class Game{
public abstract void startGame(Player player);
}
抽象类的特点:用abstract修饰,除了不能创建对象外,和普通类一样
抽象方法的特点:用abstract修饰,没有方法体,抽象子类必须重写所有抽象方法
抽象类中有构造方法吗?:有构造方法,不是通过new类调用,而是要通过创建其子类对象时调用
执行某个类的构造方法时,一定会创建当前类的对象吗?:不一定
1.如果是普通类,执行构造方法一定会创建对象
2.如果是抽象类,执行构造方法时不会创建对象,只会创建其子类对象
接口interface
接口是一种数据类型,在定义接口时,用interface替换class
接口是一个完全抽象类,能够同时继承多个接口,使用语法:implements 接口名1,接口名2...
使用接口的条件:
1.如果想要让某个类作为多个类的子类时,可以将这些仿佛类定义为接口
2.如果一个类中所有的方法都是抽象方法,那么就可以将这个类定义为接口
//定义接口
public interace 接口名{
//接口中只能定义公开的静态常量且赋值,默认用public static final修饰
double PI =3.14;
//接口中的方法默认用public abstract修饰
//接口中的方法只能使用public修饰,不能用其他的访问修饰符,不能有方法体
void fun();
//接口中不能定义普通方法
//void fun1(){}
//jdk1.8之后,接口中可以定义默认方法或者静态方法,有方法体
default void fun2(){}
static void fun3(){}
}
特点:
1.接口中的属性默认被public static final修饰,表示公共的静态常量,需要赋值,使用时直接通过类名访问。
2.接口中的方法默认被public static 修饰,表示公共的抽象方法,没有方法体
3.JDK1.8后,接口中可以存在两种特殊方法,都有方法体,被default修饰的默认方法,被static修饰的静态方法
4.接口中没有构造方法,不能创建对象
5.接口通常需要子类实现,实现后必须重写其中的所有抽象方法
抽象类和接口的异同:
抽象类是一个类,用class定义
-
有构造方法 ,但是不能创建对象,在创建子类对象时调用构造方法
-
抽象类中可以有抽象方法,也可以有普通方法
-
抽象类被子类继承时,使用extends关键字,必须重写其中的所有抽象方法
-
子类只能继承一个抽象类
接口不是一个类,用interface定义的
-
没有构造方法,不能创建对象
-
接口中的属性都是公共的静态常量
-
接口中的方法都是公共的抽象方法
-
JDK1.8后,可以在接口中定义default默认方法和static静态方法
-
接口被实现类实现时,使用implements关键字,实现类必须重写父接口中的所有抽象方法
-
实现类可以实现多个接口
相同点
-
接口和抽象类都不能创建对象
-
接口的实现类和抽象类的子类都需要重写抽象方法
static静态的
static是一个修饰符,可以修饰属性,方法以及代码块
被static修饰的内容称为静态成员。静态成员在类加载的时候,就会保存到内存中,可以脱离对象存在。访问静态成员时,可以不用创建对象,直接通过类名访问。 如Math中的属性和方法都是静态的,所以直接通过Math访问。
使用static的条件
如果某个属性或者方法被高度重用时,可以定义为静态的属性或者方法
这些属性会脱离对象,在类加载时加载到内存中,直接通过类名访问。
不想创建类对象就可以将该类的属性和方法定义为静态的,直接通过类名访问。
静态方法中无法使用非静态成员,普通方法中可以使用静态成员
可变参数
当某个方法的参数是同一类型且数量未知时,使用可变参数定义
语法:修饰符 返回值类型 方法名(数据类型... 形参){
//这时的参数数量是可变的,范围[0,+∞)
//整个参数会成为一个数组
}
特点:
1.可变参数只能在方法列表中出现一次,且在列表参数的末尾位置
2.可变参数是一个数组
3.调用方法时,传递的参数用","隔开
public class Test {
public static void sum(String str,int... nums){
int sum = 0;
for (int num : nums) {
sum+=num;
}
System.out.println(sum);
}
public static void main(String[] args) {
//调用含有可变参数的方法时,传的值用","隔开
sum("这些数字的和为:",1,2,3,4,5,6,7,8,9);
}
}
枚举enum
枚举是一个特殊的类,是一些常量的集合
语法:public enum 枚举类型名{
常量1,常量2...常量n
}
内部类
当某个方法的参数为接口时,通常会先定义该接口的实现类,在创建实现类的对象作为方法的参数,当使用匿名内部类后,就可以不用创建实现类,直接通过匿名内部类作为参数使用
错题:
public class Person{
int arr[] = new int[10];
public static void main(String[] args){
System.out.println(arr[1]);
}
}
这道题最终的结果是编译时将出现错误,因为数组是类中的成员变量,而main方法是一个静态方法,静态方法无法直接使用非静态成员,所以main方法中没有定义数组,所以编译时会出现异常。
int price = 10;
int number = 0;
int money = 0;
for(int i = 0; i<2; i++){
number++;
--price;
money+=number*price
}
System.out.println(money);
最后的输出结果是25=1*9+2*8