因为自己淋过雨,所以懂得为别人撑伞。
1、什么是面向过程?
2、什么是面向对象?
面相对象不是某一种语言的特性,而是一种编程思想。
面向对象编程的主要思想是把构成问题的各个事物分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描述一个事物在解决问题的过程中经历的步骤和行为。
在面向对象的设计中,初始元素是对象(将程序和数据封装在对象中),然后将具有共同特征的对象归纳成类(物以类聚),组织类之间的等级关系,构造类库。在应用时,在类库中选择相应的类即可。
典型的代表有:Java、C++、C#、Python、PHP等等
优点:重用性、灵活性和扩展性高。
三大基本特征:封装、继承、多态。
五大基本原则:单一职责原则、开放封闭原则、里式替换原则、接口隔离原则、依赖倒置原则。
类:可以理解成图纸,它是对象共同特征的描述。
对象:是真实存在的具体实例。
在Java中,必须先设计类,才能创建对象并使用。
public class 类名{
1、成员变量 (也可以称作属性,描述对象的特性)
2、成员方法 (包括:普通方法、静态方法,描述对象的行为)
3、构造器 (创建对象、初始化数据)
4、代码块 (包括:普通代码块{}、静态代码块static{})
5、内部类 (包括:成员内部类、局部内部类、匿名内部类和静态内部类)
}
注意事项:
使用 new
关键字来实例化一个对象(这种方式创建增加耦合度,无论使用什么框架,都要减少new的使用以降低耦合度)。
对象的功能:调用属性、调用方法。
创建对象语法格式如下:
类名 对象名 = new 类名();
例如:定义一个汽车类,属性有:名称、价格,行为有:启动、运行。
public class Car {
// 成员变量
String name;
double price;
public void start(){
System.out.println(name+"启动了");
}
public void run(){
System.out.println(price+"万的"+name+"跑起来了");
}
}
public class Test1 {
public static void main(String[] args) {
// 创建汽车对象
Car car = new Car();
// 调用属性
System.out.println(car.name);
System.out.println(car.price);
// 为属性赋值
car.name = "法拉利拉法";
car.price = 3150;
// 调用方法
car.start();
car.run();
}
}
public class Car {
// 成员变量
String name;
double price;
public void start(){
System.out.println(name+"启动了");
}
public void run(){
System.out.println(price+"万的"+name+"跑起来了");
}
}
public class Test1 {
public static void main(String[] args) {
Car c1 = new Car();
c1.name = "法拉利拉法";
c1.price = 3150;
c1.start();
c1.run();
Car c2 = new Car();
c2.name = "宝马";
c2.price = 66;
c2.start();
c2.run();
}
}
public class Student {
String name;
char sex;
String hobby;
public void study(){
System.out.println(name+"正在学习");
}
// 打印个人信息
public void show(){
System.out.println("姓名:"+name+",性别:"+sex+",爱好:"+hobby);
}
}
public class Test2 {
public static void main(String[] args) {
Student s1 = new Student();
s1.name = "小张";
s1.sex = '男';
s1.hobby = "睡觉、摸鱼";
s1.show();
s1.study();
Student s2 = s1;
s2.name = "小李";
s2.sex = '女';
s2.hobby = "唱歌";
s2.show();
s2.study();
}
}
垃圾回收:当堆内存中的对象,没有被任何变量引用(指向)时,就会被判定为内存中的“垃圾”。
构造器的声明格式如下:
修饰符 类名([参数列表]){
语句;
}
1、如果我们没有显示的声明构造器,系统会默认提供一个无参构造器。
public class Dog{
String name;
int age;
void run(){
System.out.println(name+"在草坪上奔跑!");
}
// 无参构造器
// public Dog(){}
public static void main(String[] args){
Dog dog = new Dog();
}
}
2、如果我们显示的声明了有参构造器,当我们要使用无参构造器时,需要手动把这个无参构造器声明出来。
有参构造器:在一个对象初始化的时候,给指定的属性赋值。(往往为了简便开发)
所以我们要在这个类中把无参构造器声明出来:
public class Dog{
String name;
int age;
public Dog() {
System.out.println("无参构造器");
}
void run(){
System.out.println(name+"在草坪上奔跑!");
}
public Dog(String name){
this.name=name;
}
public static void main(String[] args){
// 实例化一个Dog对象
Dog dog = new Dog();
}
}
注:构造器不可以显示调用(用类名调用),构造器在创建对象时被配调用。
this([参数列表]);
用来调用本类的构造器。this([参数列表]);
在构造中必须是第一条语句。访问级别 | 访问权限修饰符 | 同类 | 同包 | 子类 | 全局范围内 |
---|---|---|---|---|---|
公开 | public | √ | √ | √ | √ |
受保护的 | protected | √ | √ | √ | |
默认 | default | √ | √ | ||
私有 | pirvate | √ |
访问控制级别由小到大排序:private->default->protected->public。
面向对象的三大特征:封装、继承、多态。
生活中封装的例子:手机、键盘等等
封装的规则:将类的成员隐藏在类的内部,这样外部程序无法直接访问,只能通过类提供的public方法去访问类中隐藏的成员。
封装的好处:
public class Product {
// 私有化属性
private String name;
private double price;
/*
对属性进行封装,get/set
*/
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
// 无参构造器
public Product() {}
// 有参构造器
public Product(String name, double price) {
this.name = name;
this.price = price;
}
/**
* 封装一个方法:用于获取当前日期时间
*/
public String getDate(){
// 初始化Date对象
Date date = new Date();
return date.toString();
}
}
JavaBean:也可以称为实体类,其对象可以用于在程序中封装数据。
标准JavaBean须满足如下书写要求:
成员变量和局部变量的区别:
区别 | 成员变量 | 局部变量 |
---|---|---|
类中位置不同 | 类中,方法外 | 方法内 |
初始化值不同 | 有默认值,无需初始化 | 没有默认值,使用之前需要完成赋值 |
内存位置不同 | 堆内存 | 栈内存 |
生命周期不同 | 随着对象的创建而存在,随着对象的消失而消失 | 随着方法的调用而存在,随着方法的运行结束而消失 |
在所归属的大括号内{} |
final关键字是最终的意思,可以修饰类、方法、变量。
修饰类:表示该类是最终类,不能被继承。例如 :public final class String{}
修饰方法:表示该方法是最终方法,不能被重写。(因此private方法默认是final型的)
修饰变量:使用前必须被初始化;一旦被初始化,将不能再被改变(常量)。
例如 final int AGE=18;
如果final修饰的变量是引用类型:那么变量存储的地址值不能发生改变,但是地址指向的对象内容是可以发生变化的。
1、枚举类的定义格式:
修饰符 enum 枚举名称{
枚举的第一行都是罗列枚举类的对象名称,建议全部大写。
}
例如:
public enum Season {
// 枚举类的第一行默认都是罗列枚举对象的名称,建议全部大写。
SPRING,SUMMER,AUTUMN,WINTER;
}
我们通过反编译查看枚举类的代码:
2、枚举的作用: 枚举可以做信息标志和分类(缺点:不能表示字面值,表示字面值用常量)
staitc是静态的意思,可以修饰变量和方法。
在类中静态资源无法直接访问非静态的资源。
在静态方法中不能用this关键字。(因为java中的static是类区域,而this表示当前类的对象,然后static修饰的方法是由类直接调用,不需要创建对象,所以在static里不能用this)
static修饰的变量和方法不会被JVM自动回收。
静态方法不能被重写。
工具型的方法设计成static。(这样不依赖于某个对象,用类调用即可!)
static都会和final配合修饰常量。例如 public static final String USER_NAME=“张三”;
代码块
static {...}
,随着类加载的时候执行,只执行一次,并且优先于各种代码块以及构造器,用于资源初始化。{...}
,是实例代码,依赖具体的对象,在创建对象时执行。Java中用关键字extends表示继承,我们可以让一个类和另一个类建立父子关系。
格式: public Dog extends Animal {}
作用:当子类继承父类后,就可以直接使用父类公有的属性和方法。
1、使用继承的好处
2、继承设计规范
子类中相同的特征(共性属性和共性方法) 放在父类中定义,子类独有的属性和行为应该定义在子类自己里面。
先调用父类的无参构造器初始化父类数据,然后调用子类构造器(无参/有参),对象空间中先划分父类实例变量的内存,然后再划分子类实例变量内存,配合Java中单继承的约束 就可以保障每个类型的变量位置是固定不变的。
3、继承的特点
private
关键字修饰的属性和方法,但是子类不能继承父类的构造器。1、为什么需要重写?
父类的功能,子类不一定需要,或者功能不一定满足。(子类重写父类非static、private修饰的方法)
2、方法重写注意事项:
需要有继承关系,子类重写父类的方法。
方法名必须相同。
参数列表必须相同。
修饰符:范围可以扩大但不能缩小: public>protected>default>private。
抛出的异常:范围可以被缩小但不能扩大 ClassNotFoundException–>Exception(大的)。
方法重写,子类方法和父类方法必须一致,只是方法体不同。
3、方法重载和方法重写的区别
方法重载 | 方法重写 |
---|---|
overlead | override |
访问权限修饰符、返回值、异常无关 | 访问权限修饰符、异常、返回值有关 |
参数列表不同 | 方法名、参数列表相同 |
发生在同一个类 | 不同类 |
super([参数列表]);
来调用父类的构造器。this | super |
---|---|
指代当前对象 | 代表父类对象的引用 |
调用本类的构造器或方法和属性 | 调用父类的构造器或方法和属性 |
在构造器中必须是第一条语句 | 在子类构造器中必须是第一条语句 |
修饰符 abstract class 类名{
修饰符 abstract 返回值类型 方法名(形参列表);
}
示例:
// 抽象类 abstract class
public abstract class Action {
/**
* 抽象方法
* 它没有方法体,它是一种约定,让别人来实现
*/
public abstract void doSth();
// 普通方法
public void run(){
System.out.println("小明在奔跑");
}
}
// 子类继承抽象类,那么就必须要实现抽象类没有实现的抽象方法,否则该子类也要声明为抽象类
class A extends Action{
@Override
public void doSth() {
System.out.println("小明在唱歌");
}
}
JDK7以前:接口中只能放常量、抽象方法。
JDK8之后的版本:接口可以放常量、抽象方法、默认方法、静态方法。
使用interface关键字声明接口。例如: public interface UserDao{}
接口可以多实现(implement)和多继承(extends)
如果一个类实现了一个或多个接口,就必须重写接口中的所有抽象方法。(大概率的情况下:写接口、写实现类)
接口中所有的抽象方法可以省略 public abstract
。
接口中所有的变量都是常量,public static final
,可以省略不写。
常量的命名规则:所有单词的字母全大写,中间以下划线分割。如STUDENT_STATUS
接口不能被实例化,因为接口中没有构造器。
示例:
// 接口
public interface MyInterface {
// 抽象方法
void add();
void delete();
void update();
void select();
}
// 实现接口,重写接口中的所有抽象方法
public class Application implements MyInterface{
@Override
public void add() {
System.out.println("添加");
}
@Override
public void delete() {
System.out.println("删除");
}
@Override
public void update() {
System.out.println("修改");
}
@Override
public void select() {
System.out.println("查询");
}
}
抽象类和接口的区别:
区别 | 抽象类 | 接口 |
---|---|---|
关键字 | abstract | interface |
成员变量 | 可以包含任意成员变量(包括各种访问级别的类成员变量和实例变量) | 只能包含公开的静态常量(默认由 public static final 修饰) |
方法 | 除了抽象方法外还可以包含任意的方法(包括各种访问级别的类方法和实例方法 ) | 只能包含公开的抽象方法(默认由 public abstract 修饰) |
使用 | 抽象类只能被继承(关键字extends),单继承 | 接口可以被实现(关键字implements)和继承 |
多态指的是父类的某个方法被其子类重写时,可以各自产生各自的行为特征。
多态存在的三个必要条件:继承关系,重写方法,父类引用指向子类对象(向上转型) 。
示例:
//定义一个动物类作为父类
class Animal{
public void move() {
System.out.println("动物在移动!");
}
}
class Fish extends Animal{
// 重写了父类中的move方法
public void move() {
System.out.println("鱼儿在游!");
}
}
class Bird extends Animal{
// 重写了父类中的move方法
public void move() {
System.out.println("鸟儿在飞!");
}
}
class Horse extends Animal{
// 重写了父类中的move方法
public void move() {
System.out.println("马儿在跑!");
}
}
public class Application1 {
public static void main(String[] args) {
// 父类引用指向子类对象(向上转型)
Animal a1 = new Bird();
Animal a2 = new Fish();
Animal a3 = new Horse();
a1.move(); // 调用了Bird类的move方法 ,输出:鸟儿在飞!
a2.move(); // 调用了Fish类的move方法 ,输出:鱼儿在游!
a3.move(); // 调用了Horse类的move方法,输出:马儿在跑!
}
}
instanceof
关键字判断这个对象是否属于某个类。字符串常量池
当中。public class StringTest {
public static void main(String[] args) {
// 这两行代码表示底层创建了3个字符串对象,都在字符串常量池中
String s1 = "abc";
String s2 = "abc"+"def";
// 使用new的方式创建字符串对象
// 分析:这里的"def"是从哪里来的?
// 凡是双引号括起来的都在字符串常量池中有一份。
// new对象的时候一定在堆当中开辟空间。
String s3 = new String("def");
}
}
内存分配图如下:
==
比较的是两个字符串对象。
String类中的equals()方法,比较存储在两个字符串对象中的内容是否相等。
equalsIgnoreCase()方法,忽略大小写比较字符串。
public class StringTest {
public static void main(String[] args) {
String s1 = "一起学Java";
String s2 = "一起学Java";
String s3 = "aaa";
// ==双等号比较的是内存地址
System.out.println(s1 == s2); // true
System.out.println(s2 == s3); // false
String x = new String("hello");
String y = new String("hello");
System.out.println(x == y); // false
String z = null;
System.out.println("password".equals(z));//false,这种写法避免空指针异常
System.out.println(z.equals("password")); //NullPointerException
}
}
源码分析:
思路:比较地址->比较长度->比较每一个字符。
方法 | 说明 |
---|---|
String() | 创建一个空字符串 |
String(byte[] bytes) | 根据字节数组构建一个字符串 |
String(char[] chars) | 根据字符数组构建一个字符串 |
String(String str) | 复制一个字符串 |
String(StringBuffer buffer) | 根据字符缓冲区构建字符串 |
String(StringBulider bulider) | 根据字符缓冲区构建字符串 |
使用最多的方式:接使用字面值的方式创建字符串,如:String str = "hello world"
。
int length()
,返回字符串的长度;
返回下标:int indexOf(int ch)
, 返回指定数字在此字符串中的位置(下标);
int indexOf(int ch, int fromIndex)
,返回指定数字在此字符串中的位置,从指定位置开始查找;
int indexOf(String str)
,返回指定子字符在此字符串中的位置;
int indexOf(String str,int fromIndex)
,返回指定子字符在此字符串中的位置,从指定位置开始查找;
返回字符: char charAt(int index)
,返回字符串中指定位置的字符;
int lastIndexOf(int ch)
,返回指定字符在此字符串中最后一次出现处的索引,如果此字符串中没有这样的字符,则返回 -1;
int lastIndexOf(int ch, int fromIndex)
,返回指定字符在此字符串中最后一次出现处的索引,从指定的索引处开始进行反向搜索,如果此字符串中没有这样的字符,则返回 -1;
int lastIndexOf(String str)
,返回指定子字符串在此字符串中最右边出现处的索引,如果此字符串中没有这样的字符,则返回 -1;
int lastIndexOf(String str, int fromIndex)
,返回指定子字符串在此字符串中最后一次出现处的索引,从指定的索引开始反向搜索,如果此字符串中没有这样的字符,则返回 -1;
String trim()
,返回一个新字符串,这个字符串将删除原有字符串前后的半角空白字符(占一个字节,unicode编码为\u0020);
String strip()
,返回一个新字符串,这个字符串将删除原有字符串前后的全角和半角空白字符(占两个字节,unicode编码为\u3000);
bollean isEmpty()
,判断字符串是否为空;
分割字符串: String[] split(String regex)
,返回一个字符串数组,根据匹配给定的正则表达式来拆分字符串;
String toLowerCase()
,返回新一个字符串,这个字符串将原始字符串中的大写字母改为小写;
String toUpperCase()
,返回新一个字符串,这个字符串将原始字符串中的小写字母改为大写;
截取字符串: String substring(int beginIndex)
,返回新一个字符串,这个字符串包含原始字符串中从beginIndex(起始索引)到字符串的末尾的所有代码单元;(包括起始位置)
String substring(int beginIndex, int endIndex)
,返回新一个字符串,这个字符串包含原始字符串中从beginIndex(起始索引)到字符串的endIndex-1的所有代码单元。(包括起始位置,不包括结尾位置)
替换字符串: String replace(char searchChar, char newChar)
,返回一个新字符串,用 newChar 字符替换原始字符串中出现的所有 searchChar 字符;
判断当前字符串是否包含指定的字符:boolean contains(CharSequence s)
。
字符串转字符数组:char[] toCharArray()
。
判断字符串以什么字符开始:boolean startsWith(String prefix)
。
JDK1.8 API在线文档:https://www.matools.com/api/java8
1、验证码
需求:随机生成一个5位的验证码,每位可能是数字、大写字母、小写字母。
分析: 1、定义一个字符串:存储a-zA-Z0-9之间的全部字符。
2、总共循环5次,每次获取随机范围内的索引,并将获取的字符拼接起来。
public class CaptchaTest {
public static void main(String[] args) {
String str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
Random r = new Random();
String code = "";
for (int i = 0; i < 5; i++) {
int index = r.nextInt(str.length());
char c = str.charAt(index);
code += c;
}
System.out.println(code); //aW2nF
}
}
2、模拟用户登录
需求:对用户登录进行校验,最多给3次机会。
public class LoginTest {
public static void main(String[] args) {
String okLoginName = "root";
String okPassword = "123456";
Scanner sc = new Scanner(System.in);
for (int i = 1; i <= 3 ; i++) {
System.out.println("用户名:");
String name = sc.next();
System.out.println("密码:");
String pwd = sc.next();
if (name.equals(okLoginName)&&pwd.equals(okPassword)){
System.out.println("登录成功");
break;
}else {
System.out.println(" 账号或密码错误 , 你还有"+(3-i)+"次机会!");
}
}
}
}
3、手机号码屏蔽
需求:接收一个11位的手机号,将中间四位号码屏蔽。例如:139* * * *59803
public class TelphoneTest {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入一个11位的号码:");
String tel = sc.next();
// 获取前三位号码
String befor = tel.substring(0, 3); // [0,3)
// 获取后四位号码
String after = tel.substring(7); //从头截到尾
tel = befor + "****" + after;
System.out.println("屏蔽之后的手机号码为:"+tel);
}
}
StringBuffer的构造方法
构造方法 | 说明 |
---|---|
public StringBuffer() | 构造一个不带字符的字符串缓冲区,保留16个字符的空间。 |
public StringBuffer(int[] capacity) | 构建一个不带字符,但具有指定初始容量的字符串缓冲区。 |
public StringBuffer(String str) | 构建一个字符串缓冲区,并将其内容初始化为指定的字符串内容。(初始容量为:16+参数str的长度) |
StringBuffer常用方法
方法 | 说明 |
---|---|
append(String str) | 用来在字符串末尾连接一个新的字符串str |
insert(int offest,String sub) | 在指定位置插入字符串sub。 |
delete(int beginIndex,int endIndex) | 用于删除从beginIndex开始到endIndex结束之间的字符串(含beginIndex,不包含 endindex) |
reverse() | 把StringBuffer内存反转 |
toString() | 把StirngBuffer变成String |
replace(int start,int end,String str) | 使用给定String中的字符替换此字符序列的字符串中的字符 |
length() | 返回StringBuffer的长度 |
public class TestStringBuffer {
public static void main(String[] args) {
// 创建一个StringBuffer对象
StringBuffer buffer = new StringBuffer("你不要留在过去");
// 向尾部追加数据
buffer.append(",");
buffer.append("因为明天一定会到来").append("。");//链式编程
System.out.println(buffer);
}
}
与 StringBuffer 基本相同,只是线程不安全(执行效率高)。
小结
JDK8出现的,简化字符串的拼接,使用的人很少。