Author: Lao Jiu – technology big millet

Product: Check the original article

Socializing: Zhihu

Public account: Old Nine School (beginners have benefits)

Special statement: the original is not easy, without authorization shall not be reproduced or copied, if you need to reproduce can contact the author authorized

preface

Remember that after graduating from university in 1998, it was very difficult to find a job. It was definitely more difficult than the current college students to find a job. Although I graduated in accounting at school, But all the companies required were VC++, Delphi, Java (at that time Java was the latest and most fashionable), VB, Oracle database, Weblogic, EJB, etc. (at that time Servlet container like Tomcat was not on the table). And all of them require more than a year’s work~

I haven’t learned any of these technologies in school. I remember that the application development technology I learned in school is DBase 3, and there are no application development languages such as VB, VC++, Delphi and Java. School about computer programming only learned Pascal, Fortran, assembly, C, 8086/8088 microcontroller programming, still is decompiler principle, operating system principle, computer composition principle, analog circuit, digital circuit and so on. During the six-month internship after graduation, I used DBase3 database to develop the personnel report system and office water and electricity charging system for a bank.

I used to think that application development was all about database development, because database scripts are very simple, kind of like primitive English syntax, such as select… from… Where this format, if we add a subject, then formed the I select/insert/update/delete… from … where… in.. Syntax format. Can you see how simple database scripts are? I personally think as long as junior high school English pass, anyone can use the database to develop applications ah.

At that time, accounting students had to learn database programming, which was further proof that databases were really easy)

At that time, there were no training institutions for graduates like today. I spent a week learning VB by myself, then found my first job in my life, and then began to teach myself Java. Then I moved to a foreign company in Shanghai to do EPR project development. During my stay in Shanghai, I was very lucky to meet my team leader X Hui (graduated from Fudan’s Department of Planning, his real surname has been omitted). He is a great man, using JDK 1.4 version of Swing technology for our company 50 Java programmers to write an Excel application to deal with various documents (because in foreign companies are using the legal version, the boss is not willing to give us the legal version of Office, so our boss wrote an Excel application!) “, the app is very easy to use, the various design patterns are really excellent!

At that time, I could not understand the code written by the big man, so anxious that I was like ants on a hot pan. Finally, there was no way, so he shamelessly asked the boss: “Leader, what book do I need to read to be a Java master?”

“Thinking in Java!” Our niurenhui team leader only threw me this sentence.

After that, I went to the company’s KF server and found Thinking in Java Second Edition, which I read like a Bible…

Our boss didn’t lie to me: a book is good for a lifetime!

Of course, a bad book ruins one’s youth!

Over the years, if someone asks me: How can I learn to master Java? I would answer him: First read “Thinking in Java,” then read “Core Java.” These two books are enough!

Today I read Thinking in Java Fourth Edition. The role of this book is that of my hero: Bruce Eckel, an embedded major, programmer and CEO of MindView.

Note: he was an original member of the standard C++ committee — a member of the committee that produced the C++ standard, to the extent that I believe I don’t need to describe it.

His classic books are as follows:

  • Thinking in Java series
  • Thinking in C
  • Thinking in C++
  • Thinking in Python

I have read all of them except Thinking in Python. It is because I have read Bruce Eckel’s book and 10 years of Java development experience that I can say I am a Java programmer by blood.

Of course, I’m not bad at C++ either –5 years of C++ mobile game development experience, not as good as Java.

All right, let’s get back to autobiography.

As a planning department of my background, the following translation can only be regarded as a reference, please do not as a standard. If there are shortcomings, please correct and supplement. Hopefully this will help you quickly understand Bruce Eckel’s ideas.

Object description

sequence

I look at Java this way: it tries to take the programmer away from understanding the hardware level of the operating system and steer the programmer away from having to understand hardware and away from just understanding software concepts, becoming a pure “software person.”

Software craftsman can also be translated as “pure software programmer”, or “code farmer”. Of course, he also spoke about the motivation behind Java’s production — to make programming accessible to people who don’t have a background in C/C++.

Today, Java has proven to be a success: when we first learn Java, we really don’t need to know about computer organization principles, operating system principles, and so on. As a result, Java is now the programming language anyone can learn, which is why it leapfrog C++ to become the most used programming language in the world after C++. Because it only learns one idea – object-oriented programming!

Object-oriented Programming –Object Oriented Programming (OOP).

What is Java?

OOP programming is part of this movement toward using the computer as an expressive medium Medium).

So Java is a language that uses the computer as a medium for expression.

Abstract process

Most people don’t experience maladjustment when programming in an object-oriented way, so we need to explain why this happens, because it has to do with the abstraction of human thinking. The abstraction provided by the programming language, which solves the type and quantity abstraction, for “kind” means: “What is it that you are abstracting?” Assembly language is an abstraction of the underlying machine, so called “imperative” languages such as FORTRANT, BASIC and C are the abstraction of assembly language. These are improvements on assembly language, but the key abstraction is still used by programmers using computer instructions, not the structure of the problem you are trying to solve. Programmers of this era had to make connections between the machine model (the “solution space” is where the solution is implemented, such as the computer) and the problem domain, the actual problem to be solved (the “problem space” is where the real problem exists, such as the business transaction logic). The programmer must establish The association between The machine mode (in The “solution space”, Which is the place you’re implementing that solution, Such as a computer) and the model of the problem that is actually being solved (in the “problem space”, Which is the place where the problem exists, such as business. This has led to innuendo that has to be done regardless of the programming language, and the result is programs that are very difficult to write and maintain, with the side effect of creating a “programming methods” industry.

The object-oriented approach gives programmers a tool to represent elements in a problem space. This statement is a general statement that satisfies the programmer’s general presentation requirements rather than being bogged down in a particular problem. We call the elements in the problem space and their representation in the solution space “objects” (of course you can also use objects outside the problem space). Because of this idea, the program itself becomes a metaphor for the problem by adding new object types! So when we read the code to describe the solution, the words you read represent the problem. OOP programming, therefore, allows you to describe problems in problem terms themselves, rather than in computer terms. There’s a little bit of a computer connection here: every object is like a little computer — it has states, it has operations you can request! So in this respect, objects are different from real objects — they all have properties and behaviors.

If you want to do pure object-oriented programming, you need to meet the following characteristics:

  • Everything is an object. We need to think of an object as a fancy variable; This variable stores data, and you can “send a request” to the object asking it to perform an operation. In theory, you can use any conceptual component to represent the problem you are trying to solve (dogs, buildings, services, etc.) and then represent these abstract concepts as objects in your program.
  • Each object has its own memory made up of other objects. We can create new objects by putting existing objects into a package. This way, you can hide complex programs in a simple object.
  • Every object has a type. Descriptively, each object is an instance of a class, and “class” and “type” are semantically the same. Most importantly, for a class, we need to focus on: “What messages can you send to it?”
  • A program is a bunch of objects telling each other what to do by sending messages. If you need to send a request to an object, you need to “send a message” to the object. Specifically, you can think of a request message as calling a method that belongs to a particular object!
  • All objects of a particular type can receive the same messages. This statement actually means a loaded statement. Since an object of type “circle” is also an object of type “Shape”, a circle is guaranteed to receive shape messages. That is, you can write code that tells Shape to automatically handle tasks that meet the requirements of a Shape description. This concept is the most powerful concept in OOP!!

**Booch provides a more concise description of objects as follows: “An object has state, behavior and identity.” This means that An object has internal data, methods, and each object is unique, i.e. has a unique address in memory.

Objects with interfaces

Aristotole was probably the first to begin a careful study of the concept of type; He says “fishes the class of fish and the class of birds.” What he means is that all objects are unique, and they are part of the object type, and those objects have characteristics and behaviors. This idea is directly used in the first generation of programming oriented statements simulA-67 statements, the most basic keyword “class” in the program represents a new type (type).

The name Simula implies that we simulate the classical “bank teller problem.” We have a lot of cashiers, customers, accounts, transactions, and money units — they’re all a bunch of “objects.” Objects are unique in execution, and they are classified as something called “classes of objects”, which is where the keyword class comes from!

Creating abstract data types is a fundamental concept of object-oriented programming. Abstract data types are actually a bit like built-in types: you can create variables of a type (we call them objects or instances) and manipulate those variables (call sent messages or requests; You can give a message to an object and then tell the object what to do.

The members (elements) of each class are shared: for example, each account has a balance, each cashier can accept deposits, etc. At the same time, each member has its own status: each account has a different balance value; Each teller has his own name, etc. Therefore, cashiers, customers, accounts, and transactions are represented by a unique entity in the computer! This entity is an object, and each object belongs to a specific class that defines the properties and behavior of the object.

So while our job with object-oriented programming is to create new data types, we actually use the “class” key to do this. When you see the word “type”, you can convert it to “class” and vice versa.

Because a class describes a set of objects that have the same properties (data elements) and behavior (functionality), a class is a true data type. The difference between defining classes to describe problems instead of using data types described directly by memory units in a computer is that we can satisfy the problem description by adding new data types. Programming systems welcome new classes, but they need to be careful how they relate to built-in types!

Object-oriented methods are not limited to implementing simulated actions. Whether or not you agree that a program is a simulator for your design system, when we use OOP techniques, we can greatly simplify implementation problems.

In the figure above, an object can satisfy the actual request. To send a request to an object, the object must have its own interface, which is determined by the type. So my request to light the bulb is as follows:

Light light = new Light(); // Define a light bulb with the class

light.on(); // Request light to perform the action of lighting

The interface on() determines the response to your request for a specific object list. However, our code must satisfy this request somewhere. This allows the use of hidden data, which includes the concept of “implementation.” It’s not that complicated from a procedural statement point of view. A type has a method that handles all possible requests and is called when you request to send a particular request to an object. This process is commonly referred to as “sending a message” (requesting) to an object and then the object responds to the message (executing the corresponding code).

The object to which the service is provided

When we develop or need to understand a program, the best way to think of objects is as “service providers.” Your program provides services to users (client programmers, end users, etc.), and those objects use other corresponding objects to accomplish those services. Your goal is to produce (preferably in an existing code base) a set of objects that provide an ideal service for solving real-world problems!

This approach requires asking, “If I could magically pull them out of a hat, would the object solve my problem correctly? (If I could magically pull them out of a hat, what objects would solve my problem right away?) For example, if we were developing a notepad program, you might imagine that some objects contain the input screens for predetermined sheets of paper, others do the counting of those sheets, others handle the printing actions of different printers, and so on. While some of these things may be available and some may not be, what should be the status of these things (objects) that are not available? What services do these objects provide, and how do these objects need them to implement these services? If you have this mindset, then you can determine “that object seems to satisfy some of these requirements” or “I’m sure that object already exists” — this is a very reasonable way to break the problem down into a set of objects.

Thinking of an object as a service provider has another benefit: it helps us improve the cohesiveness of our objects. Because high cohesion is a fundamental requirement of software design: it represents aspects of a software component (such as an object, although this may also apply to an object library or a method) that “fit together” well. A common design problem is to make one object have too many functions. For example, when you design a check print module, you can have an object that needs to know all the functions of the print format and implement all the functions of the print machine. If you find that this is too much functionality for one object, then you need to break them up into three or more objects. Such designs are highly cohesive designs! For example, one object performs check checking, one object performs interfaces to common printers – it knows about different printers – and a third object performs tasks using services provided by these objects. Therefore, a good object-oriented design is to do one thing per object and not more !!!!

Object hides implementation details

It is helpful to understand objects if the usage scenarios for object creation are divided into two parts: class creators (who create new data types) and client programmers (consumers of classes who use these data types in their applications). The goal for the client programmer is to collect a large number of utility classes and then use them for rapid application development. The goal of the class creator is to create only classes, then expose what the client needs to the client programmer, and hide the other implementation details. Why is that? Because if it is hidden, the client programmer can’t access it, so the class creator doesn’t have to worry about changing the hidden part and affecting the client. In this way, hiding implementation details can reduce application bugs!!

Reuse the implementation details of the object

If a class is created and tested, it theoretically represents a useful unit of code. This creates situations where reuse is not as easy to use as most would like; It requires developers with experience and an understanding of how to use reusable object design. However, if you have such a design, you must want to be reused. Code reuse is the most powerful advantage that object-oriented coding languages offer.

The easiest way to reuse a class is to use its objects directly, but you can also use them in a newly created class. We call this method “creating a member Object”. If the class you are creating is made up of other objects, you can combine these objects in any way you want to create the class. Because you’re using an existing class to form a new class, the concept is called “composition” – if the composition happens dynamically, we call it aggregation. A combination is usually a has-a relationship, for example, An car has An engine.

Composition provides processing flexibility because the member objects of the newly created class are generally private and therefore not accessible to the client programmer. It is then possible for the class author to modify these member variables without affecting the distribution of the existing client code. Also, because you can modify member objects dynamically at run time, flexibility is great. With inheritance, there is no extensibility because the compiler checks for all types of problems in the inheritance structure at compile time.

Object inheritance

As far as objects go, ideal objects are a handy tool! It allows you to package data and functionality using concepts, so you can use objects to represent corresponding problems in a problem space, rather than the underlying machine language used in C to represent the problem space. These concepts are represented through the use of the keyword class and are the most basic units of the compiled language.

For subclasses that inherit from a parent class, the easiest way to extend the functionality of the parent class is to add methods that the parent class does not have; But this is not a good way, because these method superclasses may also be used. Now that we can’t add on, one thing we can think of as overriding is ways to change the behavior of primitives — that is, we can use overriding to change the behavior of primitives, so that primitives can use primitives as well. Therefore, the Shape in the figure above is modified as follows

Code mapping -Shape class

import static java.lang.System.*;
import java.awt.Color;

/** Function: Write a Shape class to demonstrate the use of inheritance
public abstract class Shape{
	protected Color color;
	
	public abstract void draw(a); // Draw the action
	public abstract void erase(a);// Erase action
	public abstract void move(a); // Move the action
	public abstract Color getColor(a); // Get the color
	public abstract void setColor(Color color); // Set the color
}
Copy the code

Code mapping -Circle class

import static java.lang.System.*;
import java.awt.Color;

/** Function: Write a Circle class to demonstrate the use of inheritance
public class Circle extends Shape{
	
	public  void draw(a){ // Draw the action
		out.println("draw() method in Circle class defined");
	}
	public  void erase(a){// Erase action
		out.println("erase() method in Circle class defined");
	}
	public  void move(a){// Move the action
		out.println("move() method in Circle class defined");
	}
	public  Color getColor(a){ // Get the color
		return color;
	}
	
	public  void setColor(Color color){ // Set the color
		this.color = color; }}Copy the code

Code mapping -Square class

import static java.lang.System.*;
import java.awt.Color;

/** function: Write a Square class to demonstrate the use of inheritance. Note: It is an abstract implementation of the class representing Square */
public class Square extends Shape{
	
	public  void draw(a){ // Draw the action
		out.println("draw() method in Square class defined");
	}
	public  void erase(a){// Erase action
		out.println("erase() method in Square class defined");
	}
	public  void move(a){// Move the action
		out.println("move() method in Square class defined");
	}
	public  Color getColor(a){ // Get the color
		return color;
	}
	
	public  void setColor(Color color){ // Set the color
		this.color = color; }}Copy the code

Code mapping -Triangle class

import static java.lang.System.*;
import java.awt.Color;

Note: It is an abstract implementation of a class representing triangles */
public class Triangle extends Shape{
	
	public  void draw(a){ // Draw the action
		out.println("draw() method in Triangle class defined");
	}
	public  void erase(a){// Erase action
		out.println("erase() method in Triangle class defined");
	}
	public  void move(a){// Move the action
		out.println("move() method in Triangle class defined");
	}
	public  Color getColor(a){ // Get the color
		return color;
	}
	
	public  void setColor(Color color){ // Set the color
		this.color = color; }}Copy the code

Code mapping -ShowShape class

import static java.lang.System.*;
import java.awt.Color;
import java.util.*;
import javax.swing.*;

/** function: write a demo class to demonstrate the use of inheritance
public class ShowShape{
	
	public ShowShape(a){
		// Use generics to demonstrate dynamic binding types at compile time
		List<Shape> list = new ArrayList<Shape>();
		demoGeneric(list);
		list.get(2).draw();// Call the method draw for objects in the container
	}
	
	private void demoGeneric(List<Shape> list){
		// Declare several objects circle objects
		Shape data = new Circle();
		list.add(data);
		data = new Square();
		list.add(data);
		data = new Triangle();
		list.add(data);
	}
	
	public static void main(String[] args){
		newShowShape(); }}Copy the code

Use polymorphism to interchange objects

When we deal with inheritance systems for types, we generally want an object to be used as a generic object, not as a specific object. As a result, we write code that doesn’t depend on a specific type. Another benefit of this is that when we add new types, we don’t affect the use of base objects – thus greatly reducing the maintenance cost of the software.

The problem with this, however, is that objects of the driven type are implemented through generic classes. For example, if we try to use a generic Shape to draw ourselves, or a generic vehicle to steer, or a generic bird to fly, the compiler doesn’t know which code needs to be executed at compile time.

If we don’t know which code is going to be executed, and you have to add a new subclass, the added code has to be different from the other methods, otherwise, the compiler can’t know exactly which code is going to be executed, so what if we need to solve the problem?

In non-OOP compilers, a technique called early binding is used to determine which birds fly, while in OOP compilers, a technique called late binding is used. When we send a message to an object, the code in that method is determined at run time. The OOP compiler cannot ensure the existence of this method and does not perform checks for parameter types and return values because it does not know what code is actually being executed. For the late binding action, Java uses special code information at the site of the actual call, so each object can use this special tag information to distinguish itself from other objects. So, when we send a message to an object, the object knows what it should do — execute the actual code.

Single inheritance

OOP programming has become very popular and important since the advent of C++, where programmers need to create their own single-inherited object trees to solve problem domains. In Java itself is a pure OOP language, it according to this need to use a single inheritance of the Object tree – all objects inherit the Object class – so as to bring a very large OOP program convenience. C++ doesn’t use single inheritance as a result of the need for backward compatibility with C, but if you want to do pure OOP programming in C++, then you must create your own object tree to solve the problem domain, that is, create your own class library to solve the problem. As a result, C++ programmers spend a lot of time designing their own interfaces. Is that good? Yes, if the problem domain requires a lot of C to solve the problem, then using C++ is very valuable! However, if there is no problem with C, then you will be more effective if you choose Java as your OOP development tool. With single inheritance, all objects have the same root, you know the basic operations that each object has, all objects can be easily created in the heap, and passing parameters is very simple. At the same time, single inheritance makes it easier to implement the garbage collector, which is an important improvement of Java over C++. Finally, single inheritance is also useful for system-level operations such as exception handling, and allows us to program with more flexibility, which is why Java is a robust language!

The container

In general, you don’t know how many objects will solve a particular problem, or how long they will last. You don’t know how these objects are stored. So how do you know how much space you need to create these objects instead of running them?

The way to solve a problem in object-oriented design is to create a new object that uses a reference to another object to solve a particular problem. Of course, we could use arrays to solve the same problem, which is the way most languages do things. However, such an object is usually called a “container” (also called a collection, but Java uses the term “container”), and the result is that you can add whatever you want to it at any time. So, we don’t need to know how many things the container can hold — we just need to create the container and let it handle the details, that is, objects are containers!

Fortunately, a good OOP language has a set of containers, each in its own package. C++ is a Standard C++ Library (Standard C++ Library) anda Standard Template Library (STL). The standard library in Java also has a large number of containers, such as the List class (ordering), the Map class (associating data with one object referring to another), the Set class (holding only the type of each object), and the queue, Tree, and Stack utility classes.

From a design point of view, we need to design a container that can be manipulated to solve real problem domains. If inheritance alone can satisfy this requirement, there is no reason to do it any other way.

Parameterized types (generics)

Before Java SE5, there was only one type of container in Java: Object. Single-inherited, that is, every Object is of type Object, so a container that uses Object represents everything it can hold, making it easy to reuse. To solve the problem of type downcasting, Java uses the parameterization mechanism technique to solve this problem. A parameterized type is a class that is automatically bound to a specified type at compile time. For example, if we use a parameterized container, then the compiler can know that Shape is not just a Shape, but that it could be a Cycle, etc. For example, ArrayList = shapes new ArrayList();

Everything is an object

Although Java is a C++ based language, Java is a much purer object-oriented language.

Manipulate objects using references

Both C++ and Java are hybrid languages, but Java’s designers don’t think that blending is as important as C++. A hybrid language is one that allows multiple programming styles to write code. C++ is a superset of C because backward compatible C is a hybrid language. It includes many features that OOP does not use, so C++ is a very complex language.

By default, the Java language is all about OOP programming, so we should have object-oriented world concepts in our heads. As a result, it will be easier to learn OOP languages.

Each programming language has its own way of dealing with elements in memory. But in The case of Java, it’s very simple; all objects are represented in a single, fixed format. Thus, if we treat everything as an object, the identity we are manipulating is really a “reference” to an object. Imagine, for example, a TELEVISION and a remote control. What we have in our hands is the TV quote — it’s connected to the TV, and when someone says “change the channel” or “turn it down,” we operate the remote control (the TV quote, because it’s not the TV itself). so

​ String s;

Indicates that only a reference is created, not an object. If you need the actual object, then you need to assign to this reference

S = “remote control”;

Or s = new String(” remote controller “);

Where objects are stored

There are five different places to store data in a computer:

  1. Register – This is the fastest access because it is located inside the processor. C and C++ allow you to use them.
  2. The stack – it exists in random access memory (RAM). The processor uses the stack pointer to use it. It is very fast to access, next to the speed of storage. As Java programmers, we must know that Java programs must run on the stack. This limitation limits the flexibility of programming programs, so for Java, we keep object references on the stack and objects themselves off the stack!!
  3. The heap – This is basically a pool of memory (also in RAM chips) where all Java objects are stored. The advantage of using the heap is that the Java compiler does not need to know the size of the object, which gives flexibility to compilation. When we need an object, we just use the Java keyword new to create it, and the JVM allocates a memory space to the object in the heap when the code executes. Flexibility comes at the cost of course: it takes more time to stack objects.
  4. Constant storage – Fixed values are usually placed directly in code, the results are not secure, and they cannot be modified. For example, ROM values in embedded systems.
  5. Non-ram storage – If data is completely outside of a program, it means that it exists even when the program is not running, that is, it can not be controlled by the program. For example, stream objects and persistent objects (such as objects that interact with databases using JDBC and Hibernate).

Special case: primitive data types

All numeric types are signed; The Boolean type has no size because it is defined as two literals true and false.

For high precision numbers, the BigInteger and BigDecimal classes are used in Java to complete the calculation. BigInteger supports an arbitrary precision integer, meaning that it can represent any integer value without losing precision. Similarly, BigDecimal can perform any fixed decimal calculation.

Java array

In Java arrays, Java guarantees that the data is instantiated and that no out-of-bounds access to the array can occur. When we create an array of objects, you actually create an array of references to them, and those references are automatically initialized to: null – when Java sees null it means that the reference does not refer to an object. However, when we need to use a reference, we must assign a value to the reference, so if the reference value is still null when used, a runtime error is reported. Thus, Java can solve the array defect problem in C and C++.

For arrays of primitive data types, the programmer allocates zero bytes of space to the array object.

Class: Creates a new data type

If everything is an object, what determines how those objects look and behave? The answer is class! This keyword means: “I want to tell you what kind of object property this is.” The syntax is as follows:

class ATypeName{     

  //Class body goes here

}
Copy the code

When we define a class, we can put elements of two types in the class: field(sometimes called member variables) and method(sometimes called member methods). A member variable can refer to any type or original data type. If the member variable is a reference type, it must be initialized before it can be used (using the new key). Each object has its own storage space for member variables; Normal member variables are not shared. Such as:

class DataOnly{

  int i;

  double d;

  boolean b;

}
Copy the code

Default values for the following raw data types:

A comprehensive demonstration of raw data type usage syntax

import static java.lang.System.*;
import java.util.*;
/** Function: Write a class that demonstrates how to use foreach. Authors: Technology Da Shu */
public class ForEachDemo{
	
	public ForEachDemo(a){
		showFloat();
		new ListCharacters();// display the letter foreach
	}
	
	private void showFloat(a){
		Random rand = new Random(47);
		float[] f =  new float[10];
		int[] integer = new int[10];
		
		for(int i = 0; i < 10; i++){
			f[i] = rand.nextFloat();
			integer[i] = rand.nextInt();
		}
		
		for(float x : f){
			out.println(x);
		}
		
		for(intx : integer){ out.println(x); }}public static void main(String[] args){
		newForEachDemo(); }}/** function: a single class is used to determine ASCII values */
class ListCharacters {
	
	public ListCharacters(a) {
		for(char c = 0; c < 128; c++){// Determine 128 ASCII characters
			// Use the Character wrapper class to judge letters
			if(Character.isLowerCase(c)){
				out.println("Values." + (int)c +
				"Letters:"+ c); }}}}Copy the code

I/O stream objects

Creating a good input/output (I/O) system is very important for language designers. Inputs and outputs may include documents, consoles, network connections, and so on, but you need to talk to these resources in a variety of ways – sequential, random, cached, binary, character, line at a time, word by word, and so on.

The File class literally means a File, but it’s not. It actually means “FilePath,” which means the name of a particular File, or a group of files in a directory. If it’s a list of files, you can use the list() method, which returns an array of String objects.

If we need to implement a directory list function, the File object can be used in two ways.

I/O flow demonstrates the code

import static java.lang.System.*;
import java.io.*;
import java.util.*;
import java.util.regex.*;

/** function: write a class to demonstrate the use of the file class. Note: use regular expressions: s. *\.java */
public class DirList{
	// Declare a member variable path
	private File path;
	// Declare a member variable named list to hold the contents of the file list
	private String[] list;
	
	public DirList(String[] args){
		path = new File(".");
		// If the command line parameter is 0
		if (args.length == 0) {// Then list the current directory table
			list = path.list();
			// display
			for(String x : list){ out.println(x); }}else{
			// If not, list according to parameters
			list = path.list(new DirFilter(args[0]));
			// Sort the list using the Arrays object
			Arrays.sort(list,String.CASE_INSENSITIVE_ORDER);
			// display
			for(String x : list){ out.println(x); }}}}class DirFilter implements FilenameFilter{
	// Declare a regular expression member variable to filter input commands
	private Pattern pattern;
	
	public DirFilter(String regex){
		pattern = Pattern.compile(regex);
	}
	/** Determine whether a file exists */ based on the input command
	public boolean accept(File dir, String name){
		returnpattern.matcher(name).matches(); }}Copy the code

File class

The purpose of the DirFilter class is to provide an Accept () method to the List method of the File class to say whether the File or directory exists — that is, whether it should be placed in the list, that is, the list method can “call back” the Accept () method to decide whether to place it in the list — an application of the policy design pattern. The matcher object that uses regular expressions in the Accept method describes what files or directories are needed.

The File class is mainly used to implement directory utility classes that list the current directory path and File contents. See the following demo class for the code

Demo class – PathPrint

import static java.lang.System.*;
import java.io.*;
import java.util.*;
import java.util.regex.*;


/** function: Write an iteration directory after the tree class author: technology big shu */
public class PathPrint{
	public static String pathFormat(Collection
        collection){
		// If there is no element
		if(collection.size() == 0) {// Return []
			return "[]";
		}
		// Otherwise all usage should be displayed
		StringBuilder message = new StringBuilder("[");
		for(Object item : collection){
			// If not, the size is not equal to 1
			if(collection.size() == 1){
				message.append("\n"); / / a newline
			}
			// Otherwise get the content
			message.append(item + "\n");
		}
		message.append("]");
		
		returnmessage.toString(); }}Copy the code

Demo class – TreeInformation

import static java.lang.System.*;
import java.io.*;
import java.util.*;
import java.util.regex.*;


/** function: write an iterated directory after the tree class author: technology big tree note: this class is the classic iteration mode code, the key idea is to put a reference to File in the collection, and there is a reference to File in the collection. * /

public class TreeInformation implements 可迭代<File>{
	public List<File> files = new ArrayList<File>();
	public List<File> dirs = new ArrayList<File>();
	
	// Lists the current directory structure
	public Iterator<File> iterator(a){
		return files.iterator();
	}
	/* Pass the member variable in the recursive algorithm */
	 void addAll(TreeInformation other){
		files.addAll(other.files);
		dirs.addAll(other.dirs);
	}
	
	/** Implements the tree iteration */
	public  TreeInformation walk(String start, String regex){
		return recurseDirs(new File(start), regex);
	}
	
	public  TreeInformation walk(File start, String regex){
		return recurseDirs(start, regex);
	}
	
	public  TreeInformation walk(File start){
		return recurseDirs(start, ". *");
	}
	
	public  TreeInformation walk(String start){
		return recurseDirs(new File(start), ". *");
	}
	
	/* Implement */ with recursion
	 TreeInformation recurseDirs(File startDir, String regex){
	 	out.println("startDir is " + startDir + ", regex is " + regex);
		TreeInformation result = new TreeInformation();
		
		for(File item : startDir.listFiles()){
			if(item.isDirectory()){ // If it is a directory
				// Add it to the list
				result.dirs.add(item);
				// Then add recursively
				result.addAll(recurseDirs(item,regex));
			}else{
				// If it is a file, use the regular expression to determine
				if(item.getName().matches(regex)){
					// Add the file to the listresult.files.add(item); }}}return result;
	}
	
	public String toString(a){
		return "Contents:" + PathPrint.pathFormat(dirs)
			+ "\n\n file:"+ PathPrint.pathFormat(files); }}Copy the code

File class – examines and creates directories

In addition to indicating the existence of a directory or File, the File object can be used to create a new directory. See the MakeDirectories class for the code

import static java.lang.System.*;
import java.io.*;

Note: Note that we use policy mode to process document objects */
	
public class MakeDirectories{
	private static void usage(a){
		StringBuilder message = new StringBuilder();
		message.append("Use format: MakeDirectories 1... \n");
		message.append("Create each path \n");
		message.append("Use the format: MakeDirectories -d path1... \n");
		message.append("Delete each path \n");
		message.append("Use format: MakeDirectories -r path1 path2\n");
		message.append("Rename path1 to path2\n");
		err.println(message.toString());
		exit(1); // Shut down the system
	}
	
	private static void fileData(File file){
		StringBuilder message = new StringBuilder();
		message.append("Absolute path:" + file.getAbsolutePath() + "\n");
		message.append("Read only:" + file.canRead() + "\n");
		message.append("Writable:" + file.canWrite() + "\n");
		message.append("getName:" + file.getName() + "\n");
		message.append("getParent: " + file.getParent() + "\n");
		message.append("getPath: " + file.getPath() + "\n");
		message.append("Length:" + file.length() + "\n");
		message.append("Last modified:" + file.lastModified());
		out.println(message.toString());
		// What is the current path
		if(file.isFile()){
			out.println("Current path is a file");
		}else{
			out.println("Current path is a directory"); }}public MakeDirectories(String[] args){
		if(args.length < 1) {// If the parameter list is less than 1
			// Then print a sentence explaining how to use this class
			usage();
		}
		/ / otherwise
		if(args[0].equals("-r")) {// If the argument is -r
			if(args.length ! =3){
				usage();
			}
			File old = new File(args[1]);
			File rename = new File(args[2]);
			old.renameTo(rename);
			fileData(old);
			fileData(rename);
			return; // Exit main thread
		}
		// Delete the directory
		int count = 0;
		boolean del = false;
		if(args[0].equals("-d")){
			count++;
			del = true;
		}
		count--;
		while(++count < args.length){
			File file = new File(args[count]);
			if(file.exists()){
				out.println(file + "It already exists.");
				if(del){
					out.println("Delete..."+ file); file.delete(); }}else{// Otherwise, it does not exist
				if(! del){ file.mkdirs(); out.println(file +"Created!!); } } fileData(file); }}}Copy the code

Input and output

Programming language I/O libraries are generally used to represent an abstraction of a flow that represents a data source like a sink that can generate and receive pieces of data, while a flow hides the implementation details of the actual I/O device.

Java’s I/O library is divided into two parts: input and output. We use InputStream or Reader as the base class for input streams, and then call read() to read a single byte or an array of bytes. The corresponding OutputStream or Write class provides the Write () method to Write a byte or an array of bytes. However, in real development, we generally don’t use these methods; We can use other interface methods to do this, primarily using the Decorator pattern.

InputStream Indicates the type of a stream

The type represented by InputStream depends on the resource:

  • An array of bytes
  • A String object
  • A file
  • A “pipeline” is a bit like physical management: you can put things in one end, and then pull out a sequence of other stream objects from the other end, and aggregate it into a single stream object
  • Other resources, such as stream objects for Internet connections (see “Thinking in Enterprise Java”)

FilterInputStream is also an InputStream object that provides the base class for a “decorator.”

OutputStream Indicates the type of a stream

Add properties and useful interfaces

In the Java I/O library, FilterInputStream and FilterOutputStream are “decorator” interface objects that control InputStream and OutputStream, respectively. The latter, however, is the key to implementing the Decorator pattern (it provides a common interface to all decorated objects).

Let’s see how to use FilterInputStream to read information from an input stream object.

The FilterInputStream class does two very important things: The first is DataInputStream, which allows us to read various primitive data types as strings (all methods start with “read”, such as readByte(), readFloat(), etc.), The corresponding DataOutputStream object is used to do this by putting these data types into another stream object.

The other types are like the internal behavior of InputStream: the last two classes support compile-time build actions, whether or not they operate on stream objects in the cache, so they cannot be used in generic programming.

PrintStream is intended to print all data types, both raw and String, using print() and println() methods. This class supports the checkError() method, but does not support internationalization or cross-platform operations, a problem solved in the PrintWriter class.

BufferedOutputStream is a caching mechanism for output streams.

Reader and Writer

The InputStream and OutputStream classes are byte-oriented I/O stream objects, while the Reader and Writer classes provide character-oriented I/O stream objects that support Unicode codes. The most important reason to use Reader and Writer is the need for internationalization. The old I/O stream objects only support 8-bit stream objects, not stream objects handling 16-bit Unicode codes, and readers and writers operate faster than the old stream objects.

Note that RandomwAccessFile is not part of the InputStream and OutputStream inheritance, but it can be moved backwards and forwards in a file. It uses the getFilePointer() method to locate the file’s current location, and seeks () to move the current pointer to a new location.

RandomAccessFileDemo demo class

import static java.lang.System.*;
import java.io.*;

/** Function: Write a tool class to process a document using RandomAccessFile. * /
public class RandomAccessFileDemo{
	
	public RandomAccessFileDemo(String fileName, String priority){
		try{
			RandomAccessFile file = new RandomAccessFile(fileName,priority);
			// Read the file line by line
			for(int i = 0; i <= 4; i++){
				out.println(file.readLine());
			}
			// Specify a current file pointer
			long current = file.getFilePointer();
			// Move according to the file pointer
			file.seek(current + 2);
			// Add content according to the moved position
			file.write("Lao Jiu School -- Technology Big Millet".getBytes());
			// Then display
			for(int i = 0; i <= 5; i++){
				out.println(file.readLine());
			}
			current = file.getFilePointer();
			file.seek(current + 2);
			file.write("27.".getBytes());
			file.close();
		}catch(Exception e){ out.println(e.getMessage()); }}}Copy the code

Formatted input demo code in memory

import static java.lang.System.*;
import java.io.*;

/** function: write a tool class for processing documents, reading content from memory. Note: This is mainly implemented by Unicode character stream objects
public class MemoryInput{
	
	public MemoryInput(String filename){
		try{
			StringReader input = new StringReader(BufferedInputFileDemo.readFile(filename));
			// Use StringReader to read Unicode codes from the cache
			int contant = 0;
			// It is then displayed on the screen using unicode codes
			while((contant = input.read()) ! = -1){
				out.print((char)contant); }}catch(Exception e){ out.println(e.getMessage()); }}}Copy the code

In general, we use the FileWriter object for file output. In practice, we use the PrintWriter object to provide formatted output.

File output demo

import static java.lang.System.*;
import java.io.*;
import com.jb.arklis.io.input.*;

/** function: Write an output document of the class author: technology big shu */
public class BasicFileOutputDemo{
	/** out indicates the output file name, and in indicates the input file name */
	public static void outputFile(String outFile, String inFile){
		try{
			// Read the file
			BufferedReader input = new BufferedReader(
				new StringReader(BufferedInputFileDemo.readFile(inFile)));
			// Output file
			PrintWriter output = new PrintWriter(
				new BufferedWriter(new FileWriter(outFile)));
			int count = 1;
			String temp;
			// Output line by line, add line number
			while((temp = input.readLine()) ! =null){
				output.println(count++ + ":" + temp);
			}
			output.close();
			// Displays the input information
			out.println(BufferedInputFileDemo.readFile(inFile));
		}catch(Exception e){ out.println(e.getMessage()); }}}Copy the code

In addition to using PrintWriter for format output, we can also use DataOutputStream and DataInputStream objects for data saving and recovery actions.

Data object input and output

import static java.lang.System.*;
import java.io.*;
import com.jb.arklis.io.input.*;

Note: Use DataOutputStream to implement */

public class StoringAndRecoveringData{
	
	public static void storeData(String outFile){
		try{
			DataOutputStream output = new DataOutputStream(
				new BufferedOutputStream(
				new FileOutputStream(outFile)));
			output.writeDouble(3.14159);// Save floating point numbers
			output.writeUTF("This is a PI value."); // Save the string
			output.writeDouble(1.41413);
			output.writeUTF("This is the square of two.");
			output.close();
			// Display the output result
			DataInputStream input = new DataInputStream(
				new BufferedInputStream(
				new FileInputStream(outFile)));
			// Use standard output to set the display
			out.println(input.readDouble());
			out.println(input.readUTF());
			out.println(input.readDouble());
			out.println(input.readUTF());
		}catch(Exception e){ out.println(e.getMessage()); }}}Copy the code

Image file in memory

import static java.lang.System.*;
import java.nio.channels.*;
import java.nio.*;
import java.io.*;
import javax.swing.*;
import static Print.*;

/** Function: write a test class to test the speed difference between a traditional stream and a new channel object
public class MappedIOTest{
	public static int numOfInts = 4000000;
	public static int numOfUbuffInts = 200000;
	// Define an abstract class for testing I/O
	public abstract static class Tester {
		private String name;
		public Tester(String name) { 
			this.name = name; 
		}
		public void runTest(a) {
			System.out.print(name + ":");
			try {
				long start = System.nanoTime();
				test();
				double duration = System.nanoTime() - start;
				System.out.format("%.2f\n", duration/1.0 e9);
			} catch(IOException e) {
				throw newRuntimeException(e); }}public abstract void test(a) throws IOException;
	}
	// Define a Tester array
	public static Tester[] tests = {
		new Tester("Stream Write(Stream object writes temp.tmp file)") {
			public void test(a) throws IOException {
				DataOutputStream dos = new DataOutputStream(
				new BufferedOutputStream(
				new FileOutputStream(new File("temp.tmp"))));
				for(int i = 0; i < numOfInts; i++) dos.writeInt(i); dos.close(); }},new Tester("Mapped Write(channel objects Write temp.tmp file)") {
			public void test(a) throws IOException {
				FileChannel fc =
				new RandomAccessFile("temp.tmp"."rw")
				.getChannel();
				IntBuffer ib = fc.map(
				FileChannel.MapMode.READ_WRITE, 0, fc.size())
				.asIntBuffer();
				for(int i = 0; i < numOfInts; i++) ib.put(i); fc.close(); }},new Tester("Stream Read(Stream object reads temp.tmp file)") {
			public void test(a) throws IOException {
				DataInputStream dis = new DataInputStream(
				new BufferedInputStream(
				new FileInputStream("temp.tmp")));
				for(int i = 0; i < numOfInts; i++) dis.readInt(); dis.close(); }},new Tester("Mapped Read(channel objects Read temp.tmp file)") {
			public void test(a) throws IOException {
				FileChannel fc = new FileInputStream(
				new File("temp.tmp")).getChannel();
				IntBuffer ib = fc.map(
				FileChannel.MapMode.READ_ONLY, 0, fc.size())
				.asIntBuffer();
				while(ib.hasRemaining()) ib.get(); fc.close(); }},new Tester("Stream Read/Write(Stream object Read/Write temp.tmp file)") {
			public void test(a) throws IOException {
				RandomAccessFile raf = new RandomAccessFile(
				new File("temp.tmp"), "rw");
				raf.writeInt(1);
				for(int i = 0; i < numOfUbuffInts; i++) {
					raf.seek(raf.length() - 4); raf.writeInt(raf.readInt()); } raf.close(); }},new Tester("Mapped Read/Write(channel objects Read/Write temp.tmp files)") {
			public void test(a) throws IOException {
				FileChannel fc = new RandomAccessFile(
				new File("temp.tmp"), "rw").getChannel();
				IntBuffer ib = fc.map(
				FileChannel.MapMode.READ_WRITE, 0, fc.size())
				.asIntBuffer();
				ib.put(0);
				for(int i = 1; i < numOfUbuffInts; i++)
					ib.put(ib.get(i - 1)); fc.close(); }}}; }Copy the code

File locks allow synchronous access to a file as a shared resource. If two threads are from different JVMS, or one is a Java thread and a native OS thread, the file lock can be implemented so that the OS process can see the lock, because the Java file lock is a direct reflection of the local OS locking mechanism!

File lock Demo

import static java.lang.System.*;
import java.nio.*;
import java.nio.channels.*;
import java.io.*;

/** function: write a class to demonstrate the use of file locks */
public class LockingMappedFiles{
	static final int LENGTH = 0x4FFFF; //128MB 0x8FFFFFF
	static FileChannel channel;
	
	public static void showFileLock(a)throws IOException{
		channel = new RandomAccessFile("testfilelock.dat"."rw").getChannel();
		// memory projection file
		MappedByteBuffer output = channel.map(FileChannel.MapMode.READ_WRITE, 0, LENGTH);
		// Write to the channel using memory projection files
		for(int i = 0; i < LENGTH; i++){
			output.put((byte)'x');
		}
		// Lock the channel
		new LockAndModify(output, 0.0 + LENGTH / 3);
		new LockAndModify(output, LENGTH / 2, LENGTH / 2 + LENGTH / 4);
	}
	
	// Define a private position class to handle the action of the lock definition file
	private static class LockAndModify extends Thread{
		private ByteBuffer buffer;
		private int start, end;
		
		// Initialize a member variable in the constructor
		LockAndModify(ByteBuffer buffer, int start, int end){
			this.start = start;
			this.end = end;
			buffer.limit(end);// Specify the cache upper limit
			buffer.position(start);// Specify the cache start location
			this.buffer = buffer.slice();
			start(); // Start the thread
		}
		
		// Override the run() method
		public void run(a){
			try{
				// Perform the lock action
				FileLock lock = channel.lock(start, end, false);
				// Display the lock result
				out.println("Locked." + start + "To" + end);
				// Perform the modification
				while(buffer.position() < buffer.limit() - 1){
					buffer.put((byte)(buffer.get() + 1));
				}
				/ / releases the lock
				lock.release();
				out.println("Released" + start + "To" + end);
			}catch(Exception e){ out.println(e.getMessage()); }}}}Copy the code

To serialize an object, we simply create outputStreams and ObjectOutpuStream objects. Then we call writeObject() to send the serialized object to OutputStream. So instead of reading serialization, we use InputStream and ObjectIntputStream.

Object serialization Demo

import static java.lang.System.*;
import java.io.*;
import java.util.*;
import static Print.*;

Note: This example uses a linked list of objects and raw data types to illustrate the effect of serialization. * /
public class Worm implements Serializable{
	private static Random rand = new Random(47);
	
	private Data[] datas = {
		new Data(rand.nextInt(10)),
		new Data(rand.nextInt(10)),
		new Data(rand.nextInt(10))};private Worm next;
	
	private char c;
	
	/* Use references to construct a linked list */
	public Worm(int i, char x){
		print("Worm constructor:" + i);
		c = x;
		if(--i > 0){
			next = new Worm(i,(char)(x + 1)); }}public Worm(a){
		print("Default constructor");
	}
	
	public String toString(a){
		StringBuilder result = new StringBuilder(":");
		result.append(c);
		result.append("(");
		for(Data x : datas){
			result.append(x);
		}
		result.append(")");
		
		if(next ! =null){
			result.append(next);
		}
		
		return result.toString();
	}
	
	public void showSerializable(a)throws Exception{
		Worm worm = new Worm(6.'a');
		print("worm = " + worm);
		// Serialize the object worm
		ObjectOutputStream output = new ObjectOutputStream(
			new FileOutputStream("worm.out"));
		output.writeObject("Worm was saved (serialized) \n");
		output.writeObject(worm);
		output.close();
		// Read the serialized object
		ObjectInputStream input = new ObjectInputStream(
			new FileInputStream("worm.out"));
		String temp = (String)input.readObject();
		// Re-construct the object through serialization
		Worm wormTwo = (Worm)input.readObject();
		print(temp + "Worm Two = " + wormTwo);
		ByteArrayOutputStream byteOutput = new ByteArrayOutputStream();
		ObjectOutputStream outTwo = new ObjectOutputStream(byteOutput);
		outTwo.writeObject("Worm serialized \n");
		outTwo.writeObject(wormTwo);
		outTwo.flush();
		// Read again -- ByteArrayInputStream and outpuStream
		ObjectInputStream inputTwo = new ObjectInputStream(
			new ByteArrayInputStream(byteOutput.toByteArray()));
		temp = (String)inputTwo.readObject();
		Worm wormThree = (Worm)inputTwo.readObject();
		print(temp + "Worm Three = " + wormThree);
		print("wormThree.getClass() is "+ wormThree.getClass()); }}class Data implements Serializable{
	private int n;
	public Data(int n){
		this.n = n;
	}
	
	public String toString(a){
		returnInteger.toString(n); }}/ / auxiliary class
public class Print {
  // Print with a newline:
  public static void print(Object obj) {
    System.out.println(obj);
  }
  // Print a newline by itself:
  public static void print(a) {
    System.out.println();
  }
  // Print with no line break:
  public static void printnb(Object obj) {
    System.out.print(obj);
  }
  // The new Java SE5 printf() (from C):
  public static PrintStream printf(String format, Object... args) {
    returnSystem.out.printf(format, args); }}Copy the code

Regular expression

Regular Expressions (Regular Expressions) was originally a standard toolkit for the Unix operating system, which is part of Unix. In Java, the String, StringBuffer, and StringTokenizer classes make it easy to use regular expressions. Regular expressions are very powerful text processing tools.

The basic concept

In broad terms, a regular expression is a way of describing what a string looks like, so you can say “If there are these things in the string, then it will match what I’m looking for”. For example, a number might have a minus sign, so you could describe it like this:

​ -?

To represent what one or more integers look like. In regular expressions, a number is described as’ \d ‘. If you use ‘\\’ in other languages, it might mean inserting a ‘\’ character, but in Java it means something different, and if you use ‘\’, you use the ‘\\\\’ expression. For the example above, we can add an expression

-? \\d+

It means there might be a minus sign, at least one number to the right of it.

Regular expressions can be used with the String class quite simply by calling the Matches method of String.

System. Out.println ("...1234. "matches (" -? \ \ d + ")); System. Out.println ("5678. "matches (" -? \ \ d + ")); System. Out.println (" +911. "matches (" -? \ \ d + ")); System. Out.println (" +911. "matches (" (- | \ \ +)? \ \ d + "));Copy the code

The third expression is not true because the ‘+’, while legal, is not in the regular expression format, so it matches a false value. In the regular expression, we use ‘()’ group, use ‘|’ said OR the relationship. so

(- | \ +)?

Can ‘-‘ or ‘+’ or not (because ‘? ‘exists as a combination of non-gluttonous expressions).

The String class also has a replacement method, replace(), which makes it very convenient to use regular expressions to replace the contents of the original String.

The following matching strategies can be used to validate the “Rudolph” string:

“Rudolph”, “[rR] udolph”, “[rR] [aeiou] [a-z] ol.”, “r.” style, and so on can be implemented.

The number of change

A quantity modifier describes the length of text read by an expression:

  1. Greedy – Greedy means that the quantity is Greedy, unless the descriptor has been modified. The goal of a gluttonous expression is to match as many expressions as possible. This has the effect of affecting the representation of the adjacent expression on the right.
  2. Reluctant(not greedy) to use? ‘indicates that the expression matches the expression in as few ways as possible, also known as lazy, minimum, non-greedy, or ungreedy matches.
  3. Possessive(All) – Used only in Java statements, it is advanced and therefore likely to be misused. It is used to prevent the regular expression from not executing and to make the regular expression execute more efficiently.

For example: ABC + the above expression seems to indicate that it matches multiple strings starting with ‘ABC’, but in fact, when you type ‘abcabcabc’, it will match three times. In fact, we need to “match at least one English character to the right starting with ab”. If so, then you have to write expressions like this: (ABC)+ In fact, regular expressions often fool us developers, it’s a language that crosses over with Java!

The Pattern and the Matcher class

In general, if you don’t want to be constrained by strings, you can use regular expression objects to handle expressions. Regular expressions must be identified by nicknames on Unix/Linux systems. The Pattern object represents a compiled version of the regular expression, and a matcher object is then produced from the object’s matcher() method and input character. The matches() method checks whether the entire input string matches. The split() method produces an array of strings; The find and lookingAt() methods are used to access matching results.

grouping

Groups are done using parentheses’ () ‘in regular expressions, and can be re-called by group numbers. Group 0 indicates that the entire expression is matched. Group 1 indicates the outermost parenthesis expression. For example, A(B(C))D Group 0 indicates ABCD, Group 1 indicates BC, and Group 2 indicates C. The groupCount() method of the Matcher class returns the number of groups, but not Group 0. The group() method returns a string with the group number 0 after the find method matches; The group(int I) method returns a string with the specified group number, or null on failure; Int start(int group) Returns the start subscript value of the group; Int end (int group) Returns the end subscript value of the group.

Start () and end ()

The start() method of the Matcher class returns the start subscript of the match, and the end method returns the end subscript of the match. In addition, an IllegalStateException is thrown if the two methods do not match successfully.

Note that the find() method positions the input character arbitrarily, but lookingAt() and matches() only exist every time the expression input starts to match. The matches() method returns success only if the entire expression matches, and the lookingAt() method returns success only if the first part of the input string matches.

Pattern Flags

The class Pattern can receive matching behavior flags when the compile() method is called:

Pattern.compile(String regex, int flag); The tag is a constant as follows:

Note: when the ‘^’ in “^ Java” is not in ‘[]’, it indicates a string that does not need to be matched again. So it’s equal to ^(Java), ^j(ava).

Split () and replace() methods

A split() input string into an array of string — this is the effect of the split method of the Pattern class. The replace method is a very useful one, especially for replacing content in text. The Matcher class has the following useful methods:

  • ReplaceFirst (String replacement) – The argument is used to replace the first matching part.
  • ReplaceAll (String replacement) – Replaces all matching parts of the parameter.
  • AppendReplacement (StringBuffer SBUf, String replacement) – Replace the SBUF one by one, not the first or all. This is a very important method that allows you to call a method to perform a replacement processing action (replaceFirst or replaceAll).
  • AppendTail (StringBuffer sbu, String replacement) – called when at least one appendReplacement method has been called.

The reset () method

Note: The replaceFirst() and replaceAll() methods are just literals, so they are not helpful if you want to perform specific replacement actions. In fact, we need to use the appendReplacement method to implement the specific replacement action. The appendTail() method is typically called after all substitutions have been performed.

The reset() method of the Matcher class can be applied to a new character sequence.

Regular expressions and Java I/O

The following example uses a regular expression to find the contents of a file, which mimics the grep command in Unix – JGrep. Java takes two parameters: a file name and a regular expression. The output is the line number with the matching string, along with the typeface and starting position number.

Scanning input information

The Scanner class constructor can take any input object, including a File object that can be used as an argument to a build method, as well as types such as InputStream and String. The purpose of Java SE5 is to define a class that has a method that reads () everything. The BufferedReader class does not have this effect.

So, after JDK 1.5, referencing a utility class called Scanner made reading easier.

Regular expression synthesis demonstration

The above content, we use a comprehensive code to demonstrate, hope to help you quickly understand.

import static java.lang.System.*;
import java.util.regex.*;
import java.util.*;

/** Function: write a test regular expression demo
public class ShowRegularExpression{
	// Use an inner class object to illustrate
	private class IntegerMath{
		public IntegerMath(a){
			out.println("\"-1234\".matches(\"-? \\\\d+\") is " + "1234".matches("-? \\d+"));
			out.println("\"5678\".matches(\"-? \\\\d+\") is " + "5678".matches("-? \\d+"));
			out.println("\"+911\".matches(\"-? \\\\d+\") is " + "+ 911".matches("-? \\d+"));
			out.println("\"+911\".matches(\"(-|\\\\+)? \\\\d+\") is " + "1234".matches("(- | \ \ +)? \\d+")); }}private class Splitting{
		private String knights = "Then, when you have found the shrubbery, you must "
			+ "cut down the mightiest tree in the forest... with ... a herring!";
		
		public Splitting(a){
			split(""); // No regular expression
			split("\\W+"); / / the characters
			split("n\\W+"); // the right side of 'n' follows a non-character
		}
		
		public Splitting(String content){
			replace(content);
		}
		
		private void split(String regex){
			out.println(Arrays.toString(knights.split(regex)));
		}
		// Test the use of the replace method of the String class
		private void replace(String content){
			out.println(knights);
			out.println(knights.replaceFirst("f\\w+",content)); // Replace each matching character
			out.println(knights.replaceAll("shrubbery|tree|herring", content)); // Replace all matching characters}}public ShowRegularExpression(a){
		//new IntegerMath(); // Demonstrate using the matches method of the String class
		//new Splitting(); // Test split string
		//new Splitting(" test character "); // Test the replace method
		//testMultiPattern(); // Test the use of multiple expressions
		//new RegularTestUtil(); // Test the regular expression tool
		//new Finding(); // Test the use of Matcher's find method
		//new Groups(); // Test the grouping effect
		//new StartEnd().showStartAndEnd(); // show the values of the start and end methods after matcher
		//new ReFlags(); // Tests the flag bit of Pattern
		//new SplitDemo(); // Test Patern's split method
		//new TheReplacements(); // demonstrate the use of the replace method
		//new Restting(); // Test the Mathcer class reset method
		//new JGrep("\\S+","ShowIOStream.java"); // to demonstrate the use of regular expressions with files
		new ThreatAnalyzer(); // Demonstrate the use of regular expressions in conjunction with the Scanner class
	}
	
	private void testMultiPattern(a){
		for(String pattern : new String[]{
			"Rudolph"."[rR]udolph"."[rR][aeiou][a-z]ol.*"."R.*"."R.+".". *"{})// Test the input data against the pattern array
			out.println("\"Rudolph\".matches(" + pattern + ") is " + "Rudolph".matches(pattern)); }}public static void main(String[] args){
		newShowRegularExpression(); }}class RegularTestUtil{
	private String pattern;
	private String content;
	private Scanner scanner;
	
	public RegularTestUtil(a){
		init(); // Initialize a member variable
		test(); // Perform the test action
	}
	
	private void init(a){
		scanner = new Scanner(System.in); // Receive input from the keyboard
		out.println("Enter regular expression:");
		// If there is no input
		pattern = scanner.nextLine();
		if(pattern == null || pattern.trim().length() == 0){
			out.println("Regular expressions and data to test please ^_^");
			// End the program
			exit(0);
		}
		// Otherwise perform the test
	}
	
	private void test(a){
		out.println("Enter test data:");
		content = scanner.nextLine();
		// Perform specific tests
		Pattern testPattern = Pattern.compile(pattern);
		Matcher matcher = testPattern.matcher(content);
		// If a match is found
		while(matcher.find()){
			// Print it out
			Print.print("Match \" " + matcher.group() +"\" Location:" 
				+ matcher.start() + "-" + (matcher.end() - 1)); }}}class Finding{
	private Matcher matcher = Pattern.compile("\\w+").matcher("Evening is full of the linnet's wings");
	
	public Finding(a){
		while(matcher.find()){
			Print.printnb(matcher.group() + "");
		}
		Print.print();
		int i = 0; 
		// demonstrate the relationship between find and group methods.
		while(matcher.find(i)){
			Print.printnb(matcher.group() + ""); i++; }}}class Groups{
	private final String poem = 
		"Twas brilling, and the slithy toves\n" +
		"Did gyre and gimble in the wabe.\n" +
		"All mimsy were the borogoves,\n" +
		"And the mome raths outgrabe.\n\n" +
		"Beware the Jubjub bird, and shu\n" +
		"The frumious Bandersnatch.";
	private Matcher matcher = Pattern.compile("(? m)(\\S+)\\s+((\\S+)\\s+(\\S+))$")
		.matcher(poem);
	
	public Groups(a){
		while(matcher.find()){
			for(int i = 0; i <= matcher.groupCount(); i++){
				Print.printnb("[" + matcher.group(i) + "]"); } Print.print(); }}}class StartEnd{
	private String input = "As long as there is injustice, whenever a\n" +
		"Targathian baby cries out, wherever a distress\n" +
		"signal sounds among the stars ... We'll be there.\n" +
		"This fine ship, and this fine crew ... \n" +
		"Never give up! Never surrender!";
	
	private class Display{
		private boolean regexPrinted = false;
		private String regex;
		Display(String regex){
			this.regex = regex;
		}
		
		void display(String message){
			if(! regexPrinted){ Print.print(regex); regexPrinted =true; } Print.print(message); }}public void examine(String content, String regex){
		Display display = new Display(regex);
		Pattern pattern = Pattern.compile(regex);
		Matcher matcher = pattern.matcher(content);
		// Match query
		while(matcher.find()){
			display.display("find() '" + matcher.group() + "' start = "
			 + matcher.start() + " end = " + matcher.end());
		}
		// If you are looking for it
		if(matcher.lookingAt()){
			display.display("lookingAt() start = " + matcher.start() +
				" end = " + matcher.end());
		}
		// If it matches
		if(matcher.matches()){
			display.display("matches() start = " + matcher.start() +
				" end = "+ matcher.end()); }}void showStartAndEnd(a){
		for(String in : input.split("\n")){
			Print.print("Input: + in);
			for(String regex : new String[]{"\\w*ere\\w*"."\\w*ever"."T\\w*"."Never.*? !"}){ examine(in, regex); }}}}class ReFlags{
	private Pattern pattern = Pattern.compile("^j(ava)",Pattern.CASE_INSENSITIVE|Pattern.MULTILINE);
	
	public ReFlags(a){
		Matcher matcher = pattern.matcher("java has regex\nJava has regex\n" +
			"JAVA has pretty good regular expressions\n" + 
			"Regular expressions are in Java");
		while(matcher.find()){ out.println(matcher.group()); }}}class SplitDemo{
	private String input = "This!! unusual use!! of exclamation!! points";
	
	public SplitDemo(a){
		out.println(Arrays.toString(Pattern.compile("!!!!!").split(input)));
		out.println(Arrays.toString(Pattern.compile("!!!!!").split(input,3))); }}class TheReplacements{
	// Read the resource file
	private String temp = TextFile.read("src/com/jb/arklis/reg/TheReplacements.java");
	// Match terminator, replace /*... */ string
	private Matcher matcher = Pattern.compile("/ \ \ *! (. *)! \ \ * /",Pattern.DOTALL).matcher(temp);
	
	public TheReplacements(a){
		// If there are matching characters
		if(matcher.find()){
			// Get the first group
			temp = matcher.group(1);
		}
		// Replace two Spaces with one space
		temp = temp.replaceAll("{2}"."");
		// Change the beginning of each line to a non-space -- this is just a literal, no substitution is performed!!
		temp = temp.replaceAll("(? m)^ +"."");
		// Replace the aeiou character with VOWEL1 -- this is just a literal, no replacement action is performed!!
		temp = temp.replaceFirst("[aeiou]"."(VOWEL1)");
		
		StringBuffer message = new StringBuffer();
		Pattern pattern = Pattern.compile("[aeiou]");
		Matcher tempMatcher = pattern.matcher(temp);
		// Process the information found
		while(tempMatcher.find()){
			// Actually perform the replacement method appendReplacement!! Replace vowels with capital letterstempMatcher.appendReplacement(message,tempMatcher.group().toUpperCase()); } tempMatcher.appendTail(message); out.print(message); }}class Restting{
	private Matcher matcher = Pattern.compile("[frb][aui][gx]").matcher("fix the rug with bags");
	
	public Restting(a){
		while(matcher.find()){
			out.print(matcher.group() + "");
		}
		out.println();
		// Create a new line of matched string values
		matcher.reset("fix the rig with rags");
		while(matcher.find()){
			out.print(matcher.group() + ""); }}}class JGrep{
	private Pattern pattern;
	private Matcher matcher;
	
	public JGrep(String regex,String fileName){
		// Initialize a member variable
		pattern = Pattern.compile(regex);
		// The definition requires a line number
		int index = 0;
		matcher = pattern.matcher("");
		/ / to find
		for(String line : new TextFile(fileName)){
			matcher.reset(line);
			while(matcher.find()){
				out.println("The first" + ++index + "Line." + matcher.group()
					+ "Starting position :"+ matcher.start()); }}}}Copy the code

Save the object

The simplest programs have only fixed objects that exist throughout the life of the program. We don’t know how big the program will be, so we need some kind of container to hold these objects.

In A Java collection (container), a Map is an associative array that uses one object to represent another object, and the Java container classes automatically resize the array. Container classes are the basic tools in Java that make program variables very powerful.

In Java, because of the Collection interface, we use “container” to talk about Collection objects.

Let’s use code to demonstrate object saving.

import static java.lang.System.*;
import java.util.*;

/** Function: Write a class to demonstrate generic and non-generic programming
public class ShowGenericType{
	
	public ShowGenericType(a){
		// Use non-generic types
		//showWithOutGenerics();
		// Use generics
		//showWithGenericType();
		// Shows the type conversion for generics
		showGenericTypeUpcase();
	}
	
	// Use non-generic programming
	@SuppressWarnings("nuchecked")
	private void showWithOutGenerics(a){
		List apples = new ArrayList();
		for(int i = 0; i < 3; i++){
			apples.add(new Apple());
		}
		/ / add Orange
		apples.add(new Orange());
		/ / display the Apple
		for(int i = 0; i < apples.size(); i++){
			out.println("The current Apple count is:"+ ((Apple)apples.get(i)).id()); }}// Use generic programming
	private void showWithGenericType(a){
		List<Apple> apples = new ArrayList<Apple>();
		for(int i = 0; i < 3; i++){
			apples.add(new Apple());
		}
		/ / add Orange
		//apples.add(new Orange());
		/ / display the Apple
		for(int i = 0; i < apples.size(); i++){
			out.println("The current Apple count is:"+ ((Apple)apples.get(i)).id()); }}// Describe generic type conversions
	private void showGenericTypeUpcase(a){
		List<Apple> apples = new ArrayList<Apple>();
		apples.add(new GrannySmith());
		apples.add(new Gala());
		apples.add(new Fuji());
		apples.add(new Braeburn());
		// Displays objects in the container
		for(Apple x: apples){
			out.println("The object in the current container is:"+ x); }}public static void main(String[] args){
		newShowGenericType(); }}// Declare a class to demonstrate generics and non-generics
class Apple{
	private static long counter;
	private final long id = counter++;
	
	public long id(a){
		returnid; }}class Orange{
	private static long counter;
	private final long id = counter++;
	
	public long id(a){
		returnid; }}///////////// The following classes are used to illustrate type conversions for generics
class GrannySmith extends Apple{}class Gala extends Apple{}class Fuji extends Apple{}class Braeburn extends Apple{}Copy the code

conclusion

After we save objects using collections, and then add object serialization and deserialization operations, we have the ability to write stand-alone applications. At this point, we don’t need to learn about databases, because we already know how to persist objects.

I think the next thing to learn is that object-oriented programming, design patterns are the core essence of Java. The idea of object-oriented programming is perfectly reflected in the Java Swing framework. Therefore, I recommend people who need to quickly master Java to read the book Core Java™ Volume II — Advanced Features, Eighth Edition. This book is a comprehensive overview of the core features of Java 2, which have been at the core of all subsequent versions of Java. They have been the foundation of Java’s evolving core features, and they have been in the core of Java up to the present version of Java 17!

The last

Feel useful students, please remember to big millet ❤️ attention + like + collection + comment + forward ❤️

Author: Lao Jiu School – technology big millet

Copyright belongs to the author. Commercial reprint please contact the author for authorization, non-commercial reprint please indicate the source.