Khung web hỗ trợ các luồng ảo JDK19, Phần 2: Phát triển hoàn chỉnh ứng dụng quarkus hỗ trợ các luồng ảo
In lạiTác giả: Tôi là chú chim nhỏThời gian cập nhật: 2023-09-14 15:02:09274
Chào mừng đến với GitHub của tôi
Toàn bộ tác phẩm gốc của Xin Chen (bao gồm cả mã nguồn hỗ trợ) đều được phân loại và tổng hợp tại đây: https://github.com/zq2599/blog_demos.
Tổng quan về bài viết này
Bài viết này là phần giữa của loạt bài "Web Framework hỗ trợ các luồng ảo JDK19". Trong bài viết trước, chúng tôi đã trải nghiệm một dịch vụ web có hỗ trợ luồng ảo. Sau khi thử nghiệm, chúng tôi nhận thấy rằng không có sự khác biệt rõ ràng về hiệu suất giữa nó và dịch vụ này. Hai kiến trúc web phổ biến khác trong trường hợp này có cần thiết phải nghiên cứu và học hỏi không?
Tất nhiên là cần thiết và chúng ta cần hiểu sâu hơn về sự khác biệt giữa luồng ảo và luồng thông thường thông qua chiến đấu thực tế. Trước khi các khung và thư viện chính hỗ trợ rộng rãi các luồng ảo, chúng ta phải đặt nền tảng lý thuyết và thực tiễn vững chắc. mục tiêu của loạt bài này.
Để hiểu sâu hơn, trước tiên chúng ta hãy đặt nền tảng trong bài viết này: giải thích chi tiết cách phát triển các chức năng web được đề cập ở trên.
Để làm nổi bật những điểm chính, đây là phần giới thiệu trước. Từ góc độ mã hóa, nó sẽ được giải thích rõ ràng về cách kích hoạt hỗ trợ luồng ảo. Nó thực sự rất đơn giản, như được hiển thị bên dưới. trong khuôn khổ quarkus. Mỗi khi nhận được yêu cầu web, các chủ đề trong nhóm luồng có trách nhiệm phản hồi. Có nhiều dịch vụ web hơn ở bên phải. @RunOnVirtualThread chú thích, nó sẽ trở thành một luồng ảo mới được tạo để xử lý các yêu cầu web. Có, việc sử dụng các luồng ảo trong khung quarkus thật đơn giản.
Ở bài viết trước chúng ta cũng đã thấy sự khác biệt về các thread chịu trách nhiệm phản hồi web trong 2 dịch vụ web trên thông qua giá trị trả về như hình bên dưới, có thể dễ dàng nhận thấy sự khác biệt giữa thread pool và virtual thread ngay từ tên thread.
Nhìn thấy điều này, bạn có thể nói: Thế thôi à? Bạn có thể viết một bài về một việc gì đó mà chỉ cần một lời bình luận là có thể làm được? Đây chẳng phải là sự lãng phí thời gian của tác giả và của độc giả sao?
Thật vậy, để kích hoạt các luồng ảo, chỉ cần một dòng mã hóa. Tuy nhiên, hiện tại, các luồng ảo chỉ dành riêng cho JDK19 và chúng chỉ là một chức năng xem trước. Thật không dễ dàng để kích hoạt chúng trong quá trình hoạt động thực tế. các khía cạnh của JDK, maven, IDE, v.v. Tất cả các cài đặt có liên quan phải được thực hiện và nếu bạn muốn tạo một hình ảnh docker giống như hình ảnh trước đó, chỉ cần docker chạy trong một dòng Bạn có thể khởi động luồng ảo bằng cách chạy lệnh và bạn cũng cần thực hiện điều gì đó trên Dockerfile (hình ảnh cơ bản do quarkus cung cấp không có phiên bản JDK19 và lệnh khởi động cũng cần được điều chỉnh).
Trên đây là những điểm chính của bài viết này Xin Chen đã sắp xếp chúng một cách rõ ràng. Tiếp theo, chúng ta hãy cùng nhau thực hành để làm cho trang web mà chúng ta đã trải nghiệm ở bài viết trước trở lại từ đầu, sau đó chạy trơn tru và đáp ứng được mong đợi.
Toàn bộ quá trình phát triển được hiển thị trong hình bên dưới. Tổng cộng có mười bước. Hãy bắt đầu.
môi trường phát triển
Máy tính phát triển: MacBook Pro M1, macOS Monterey 12.6
IDE: IntelliJ IDEA 2022.3 EAP (Ultimate Edition) (tức là phiên bản xem trước sớm trước khi phát hành)
Ngoài ra, khi phát triển và chạy các ứng dụng JDK19 trên máy tính có chip M1, bạn sẽ không gặp bất kỳ thay đổi nào so với X86 thông thường. Chỉ có một điều cần lưu ý: khi tải hình ảnh docker lên hub.docker.com, kiến trúc hệ thống của. hình ảnh là ARM nên không thể chạy được hình ảnh sau khi tải xuống máy tính X86.
Tải xuống JDK19
Tải xuống jdk19. Vì máy tính có chip M1 nên jdk tôi chọn là phiên bản azul. Địa chỉ là: https://www.azul.com/downloads/?package=jdk#download-openjdk.
Không có sự khác biệt giữa việc sử dụng jdk của azul và phiên bản oracle trước đó, ít nhất bạn không thể cảm nhận được điều đó trong môi trường phát triển. Chúng ta hãy xem tuyên bố chính thức của azul.
Trên thực tế, jdk của azul rất toàn diện. Các gói cài đặt cho từng phiên bản nền tảng của chip x86 đều được cung cấp. Bạn có thể chọn tải xuống tùy theo môi trường máy tính của mình.
Sau khi tải về nhấn đúp chuột để cài đặt
Sửa đổi cấu hình maven
Tôi đang sử dụng maven cục bộ ở đây và JDK tương ứng của nó cần được thay đổi thành 19. Phương pháp sửa đổi là điều chỉnh các biến môi trường. Trang chủ JAVA , trỏ nó vào thư mục JDK19 (trên máy tính của tôi, biến môi trường là ~/.zshrc TRONG)
Sau khi sửa đổi, làm cho các biến môi trường có hiệu lực và sau đó thực hiện lệnh để xác nhận rằng JDK19 đã được sử dụng
➜ ~ mvn -version Apache Maven 3.8.5 (3599d3414f046de2324203b78ddcf9b5e4388aa0) Trang chủ Maven: /Users/zhaoqin/software/apache-maven-3.8.5 Phiên bản Java: 19, nhà cung cấp: Azul Systems, Inc., thời gian chạy: /Library/Java/JavaVirtualMachines/zulu-19.jdk/Contents/Home Ngôn ngữ mặc định: zh_CN_#Hans, mã hóa nền tảng: UTF-8 Tên hệ điều hành: "mac os x", phiên bản: "12.6", kiến trúc: "aarch64", họ: "mac"
Tạo dự án Quarkus
Mở IDEA, tạo một dự án mới và chọn dự án Quarkus
Tiếp theo, chọn gói mở rộng sẽ sử dụng (thực ra là thêm các phụ thuộc jar vào trang đồ họa). Máy khách PostgreSQL phản ứng Và Jackson phản ứng RESTEasy
Bấm vào góc dưới bên phải của hình ảnh trên Tạo nên Sau khi nhấn nút, dự án bắt đầu được tạo. Sau một thời gian chờ đợi, quá trình tạo dự án đã hoàn tất, như hình bên dưới, lúc này tôi chỉ có thể thở dài: quarkus thật chu đáo. cũng có nhiều phiên bản khác nhau của tệp Dockerfile và cũng có các cấu hình liên quan đến git, thậm chí cả README cũng được viết chi tiết như vậy, tôi có thể nhấp vào nó không? chạy Nút trực tiếp chạy chương trình.
cài đặt IDEA
Vì JDK19 được sử dụng nên các cài đặt sau cần được kiểm tra và xác nhận.
Đầu tiên là cài đặt Project, như hình bên dưới
Tiếp theo là cài đặt Mô-đun. Đầu tiên hãy định cấu hình trang tab Nguồn.
Tiếp theo là trang tab Phụ thuộc
Vào menu cài đặt hệ thống IDEA
Như được hiển thị bên dưới, ba vị trí cần được đặt
Quá trình thiết lập đã hoàn tất, hãy bắt đầu viết mã
mã hóa
Đầu tiên hãy xác nhận pom.xml, được IDEA tạo cho chúng tôi. Nội dung như sau. Có hai thay đổi sẽ được thảo luận sau.
4.0.0com.bolingcavalryquarkus-virual-threads-demo1.0-SNAPSHOT3.8.1191919UTF-8UTF-8quarkus-bomio.quarkus.platform2.13.2.Finaltrue3.0.0-M7${quarkus.platform.group-id}${quarkus.platform.artifact-id}${quarkus.platform.version}pomimportio.quarkusquarkus-resteasy-reactive-jacksonio.quarkusquarkus-reactive-pg-clientio.quarkusquarkus-arcio.quarkusquarkus-resteasy-reactivenet.datafakerdatafaker1.6.0io.quarkusquarkus-junit5testio.rest-assuredrest-assuredtest${quarkus.platform.group-id}quarkus-maven-plugin${quarkus.platform.version}truebuildgenerate-codegenerate-code-tests19 19--enable-preview--enable-preview --add-opens java.base/java.lang=ALL-UNNAMEDmaven-compiler-plugin${compiler-plugin.version}-parametersmaven-surefire-plugin${surefire-plugin.version}org.jboss.logmanager.LogManager${maven.home}maven-failsafe-plugin${surefire-plugin.version}integration-testverify${project.build.directory}/${project.build.finalName}-runner org.jboss.logmanager.LogManager${maven.home}bản địabản địafalsebản địa-- Dưới đây là các tính năng mới liên quan đến luồng ảo, bắt đầu --> 19 19--enable-preview--enable-preview --add-opens java.base/java.lang=ALL-UNNAMEDmaven-compiler-plugin${compiler-plugin.version-tham sốmaven-surefire-plugin${surefire-plugin.versionorg.jboss.logmanager.LogManager< /java.util.logging.manager> ${maven.homemaven-failsafe-plugin${surefire-plugin.version kiểm tra tích hợpxác minh${project.build.directory}/${project.build.finalName}-runner org.jboss.logmanager.LogManager ${maven.homegốcgốcfalsegốc -- Dưới đây là các tính năng mới liên quan đến luồng ảo, bắt đầu --> 19 19--enable-preview--enable-preview --add-opens java.base/java.lang=ALL-UNNAMEDmaven-compiler-plugin${compiler-plugin.version-tham sốmaven-surefire-plugin${surefire-plugin.versionorg.jboss.logmanager.LogManager< /java.util.logging.manager> ${maven.homemaven-failsafe-plugin${surefire-plugin.version kiểm tra tích hợpxác minh${project.build.directory}/${project.build.finalName}-runner org.jboss.logmanager.LogManager ${maven.homegốcgốcfalsegốc trang chủ> maven-failsafe-plugin${surefire-plugin.version}integration-testverify${project.build.directory}/${project.build.finalName}-runner org.jboss.logmanager.LogManager${maven.home}bản địabản địafalsebản địa trang chủ> maven-failsafe-plugin${surefire-plugin.version}integration-testverify${project.build.directory}/${project.build.finalName}-runner org.jboss.logmanager.LogManager${maven.home}bản địabản địafalsebản địa
Thay đổi đầu tiên đối với pom.xml như được hiển thị bên dưới. 19
Thay đổi thứ hai là thêm các tham số cấu hình bổ sung vào plug-in quarkus-maven-plugin, như được hiển thị trong hộp màu đỏ bên dưới
Tiếp theo, thêm tệp cấu hình application.properties, vào tài nguyên dưới thư mục
Có hai lớp mô hình tương ứng với cơ sở dữ liệu. Lớp đầu tiên là liệt kê trường giới tính.
gói com.bolingcavalry.model; enum công khai Giới tính { NAM, NỮ; }
Lớp thực thể tương ứng với bảng
gói com.bolingcavalry.model; nhập io.vertx.mutiny.sqlclient.Row; lớp công khai Person { private Long id; private String name; private int age; private Gender gender; private Integer externalId; public String getThreadInfo() { return threadInfo; } public void setThreadInfo(String threadInfo) { this.threadInfo = threadInfo; } private String threadInfo; public Person() { } public Person(Long id, String name, int age, Gender gender, Integer externalId) { this.id = id; this.name = name; this.age = age; this.gender = gender; this.externalId = externalId; this.threadInfo = Thread.currentThread().toString(); } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Gender getGender() { return gender; } public void setGender(Gender gender) { this.gender = gender; } public Integer getExternalId() { return externalId; } public void setExternalId(Integer externalId) { this.externalId = externalId; } public static Person from(Row row) { return new Person( row.getLong("id"), row.getString("name"), row.getInteger("age"), Gender.valueOf(row.getString("gender")), row.getInteger("external_id")); } }
Tiếp theo là lớp dao để vận hành cơ sở dữ liệu. Có thể thấy phương thức hoạt động vẫn còn rất nguyên thủy, bạn phải viết mã SQL bằng tay và thực tế khi giải nén nó phải khớp từng trường một. , quarkus cũng hỗ trợ JPA, nhưng bài viết này sử dụng trình điều khiển cơ sở dữ liệu đáp ứng, do đó nhóm kết nối PGPool do Vert.x tạo ra sẽ được sử dụng.
gói com.bolingcavalry.repository; nhập com.bolingcavalry.model.Person; nhập io.vertx.mutiny.pgclient.PgPool; nhập io.vertx.mutiny.sqlclient.Row; nhập io.vertx.mutiny.sqlclient.RowSet; nhập io.vertx.mutiny.sqlclient.Tuple; nhập javax.enterprise.context.ApplicationScoped; nhập javax.inject.Inject; nhập java.util.ArrayList; nhập java.util.List; @ApplicationScoped lớp công khai PersonRepositoryAsyncAwait { @Inject PgPool pgPool; công khai Person findById(ID dài) { RowSet rowSet = pgPool .preparedQuery("CHỌN id, tên, tuổi, giới tính, external_id TỪ person NƠI id = $1") .executeAndAwait(Tuple.of(id)); Danh sách persons = iterateAndCreate(rowSet); trả về persons.size() == 0 ? null : persons.get(0); } private Danh sách iterateAndCreate(RowSet rowSet) { Danh sách persons = new ArrayList<>(); for (Row row : rowSet) { persons.add(Person.from(row)); } return persons; } }
Tiếp theo là lớp dịch vụ web VTPersonResource.java được thấy trong ảnh chụp màn hình trước đó, được chú thích @RunOnVirtualThread Sửa đổi, cho biết mã phản hồi được thực thi trong luồng ảo sau khi nhận được yêu cầu web
gói com.bolingcavalry.resource; nhập com.bolingcavalry.model.Person; nhập com.bolingcavalry.repository.PersonRepositoryAsyncAwait; nhập io.smallrye.common.annotation.RunOnVirtualThread; nhập javax.inject.Inject; nhập javax.ws.rs.GET; nhập javax.ws.rs.Path; nhập javax.ws.rs.PathParam; @Path("/vt/persons") @RunOnVirtualThread lớp công khai VTPersonResource { @Inject PersonRepositoryAsyncAwait personRepository; @GET @Path("/{id}") công khai Person getPersonById(@PathParam("id") Long id) { trả về personRepository.findById(id); } }
Cuối cùng, có lớp dịch vụ web thông thường PoolPersonResource.java để so sánh. Đây là một phương pháp thông thường để lấy một luồng từ nhóm luồng để thực thi mã phản hồi.
gói com.bolingcavalry.resource; nhập com.bolingcavalry.model.Person; nhập com.bolingcavalry.repository.PersonRepositoryAsyncAwait; nhập io.smallrye.common.annotation.RunOnVirtualThread; nhập javax.inject.Inject; nhập javax.ws.rs.GET; nhập javax.ws.rs.Path; nhập javax.ws.rs.PathParam; @Path("/pool/persons") lớp công khai PoolPersonResource { @Inject PersonRepositoryAsyncAwait personRepository; @GET @Path("/{id}") công khai Person getPersonById(@PathParam("id") Long id) { trả về personRepository.findById(id); } }
Đến đây quá trình mã hóa hoàn tất
Cài đặt khởi động IDEA
Sau khi mã hóa xong, khởi động ứng dụng trên IDEA để gỡ lỗi cục bộ là thao tác cơ bản của chúng ta, vì vậy môi trường chạy IDEA cũng phải được thiết lập để hỗ trợ tính năng xem trước của JDK19
Mở lớp mục nhập, nhấp vào mũi tên màu xanh lá cây phía trước phương thức chính và chọn Sửa đổi cấu hình chạy
Trên trang cài đặt của ứng dụng đang chạy, hãy thực hiện như sau
đã chọn Thêm tùy chọn VM
Điền nội dung được chỉ bởi mũi tên trong hình bên dưới
Cuối cùng, quá trình thiết lập đã hoàn tất, bây giờ là lúc khởi động ứng dụng
Khởi chạy và xác minh
Trước khi khởi động ứng dụng, vui lòng xác nhận rằng cơ sở dữ liệu postgresql đã được khởi động và dữ liệu đã được nhập. Vui lòng tham khảo bài viết trước để biết các phương pháp khởi động và nhập cụ thể.
Nhấp vào nút có mũi tên màu đỏ trong hình bên dưới để chạy ứng dụng trong IDEA
Địa chỉ truy cập trình duyệt: http://localhost:8080/vt/persons/1, như hiển thị bên dưới, phù hợp với mong đợi
Trong bài viết trước, chúng tôi đã chạy ứng dụng trên docker. Ngoài ra, trong các tình huống thực tế, việc các ứng dụng chạy trong môi trường docker hoặc k8s cũng là điều bình thường. và xác minh nó.
Xây dựng hình ảnh
Khi tạo dự án, IDEA tự động tạo nhiều tệp Dockerfile bằng mẫu quarkus.
Nếu JDK hiện đang sử dụng không phải là 19 mà là 11 hoặc 17 thì Dockerfile trong hộp màu đỏ ở trên có thể được sử dụng trực tiếp. Tuy nhiên, vì JDK mà chúng ta sử dụng ngày nay phải là 19 nên các Dockerfile này không thể được sử dụng và bạn phải tự mình sử dụng. Viết một cái, lý do rất đơn giản, gõ . Mở Dockerfile.jvm, như được hiển thị bằng mũi tên màu đỏ trong hình bên dưới. Hình ảnh cơ sở là jdk17, nhưng không có JDK19 trong kho này, điều đó có nghĩa là quarkus chưa phát hành phiên bản JDK19 của hình ảnh cơ sở. Ngoài ra lệnh khởi động container cũng là để điều chỉnh bạn cần thêm vào. --bật-xem-trước Để kích hoạt luồng ảo của JVM
Tệp Dockerile tôi đã viết có tên là Dockerfile.19 , nội dung như sau, có thể thấy rất đơn giản: đầu tiên thay đổi image cơ sở, sau đó sao chép kết quả mvn build và cuối cùng thêm lệnh khởi động và thế là xong (tiết kiệm dung lượng ít hơn nhiều so với bản dựng lớp chính thức , nhưng trước khi giải pháp nhân bản JDK19 chính thức xuất hiện, trước tiên hãy thực hiện những điều sau)
TỪ openjdk:19 ENV NGÔN NGỮ='en_US:en' # Hướng dẫn sử dụng WORKDIR application COPY --chown=185 target/*.jar ./ RUN mkdir config EXPOSE 8080 USER 185 ENTRYPOINT ["java", "-jar", "--enable-preview", "quarkus-virual-threads-demo-1.0-SNAPSHOT-runner.jar"]
Tiếp theo, bạn có thể tạo hình ảnh. Hãy đảm bảo rằng docker đang chạy trên máy tính của bạn.
Đầu tiên là biên dịch và đóng gói maven thông thường (uber-jar có nghĩa là jar được tạo chứa tất cả các thư viện phụ thuộc).
Hình ảnh được tạo thành công và đầu ra của giao diện điều khiển như dưới đây
Nếu bạn có tài khoản hub.docker.com thì cũng có thể đẩy lên kho công cộng như mình để thuận tiện cho mọi người.
Kiểm tra ngoại lệ (điều gì xảy ra nếu không có tham số bật-xem trước?)
Nhìn lại lệnh khởi động ứng dụng trong Dockerfile, vì các luồng ảo là một tính năng xem trước của JDK19 nên bạn phải thêm lệnh được trỏ bằng mũi tên màu đỏ trong hình bên dưới. --bật-xem-trước các tham số để chức năng luồng ảo có hiệu lực
Vì vậy tôi đã nghĩ: Điều gì sẽ xảy ra nếu tôi không thêm thông số này? Tức là, luồng ảo không được kích hoạt nhưng nó được sử dụng trong mã, vậy điều gì sẽ xảy ra khi nó thực sự chạy?
Đoán một cách mù quáng cũng vô ích. Hãy thử và xóa nó trong thông số khởi động. --bật-xem-trước , như hiển thị bên dưới, sau đó xây dựng lại hình ảnh
Chạy container như trước (một lần nữa, hãy đảm bảo cơ sở dữ liệu bình thường), sau đó truy cập nó trong trình duyệt http://localhost:8080/vt/persons/1 , trang hiển thị bình thường và dường như các chức năng không bị ảnh hưởng.
tái sử dụng Nhật ký docker Lệnh xem nhật ký nền. Như được hiển thị bằng mũi tên trong hình bên dưới, quarkus đưa ra lời nhắc ở mức WARN: Vì máy ảo hiện tại không hỗ trợ các luồng ảo nên việc chặn mặc định được sử dụng để thực thi logic nghiệp vụ.
Tóm tắt: Nếu bạn buộc sử dụng luồng ảo trong môi trường không hỗ trợ luồng ảo, quarkus sẽ chọn phương thức tương thích để tiếp tục hoàn thành nhiệm vụ.
Tóm tắt và triển vọng
Tại thời điểm này, một ứng dụng quarkus hoàn chỉnh đã được phát triển. Ứng dụng sử dụng các luồng ảo để đáp ứng các yêu cầu trên web. Hơn nữa, với tiền đề là quarkus vẫn chưa cung cấp giải pháp chính thức, chúng tôi vẫn hoàn thành việc sản xuất hình ảnh docker. Vì tò mò, chúng tôi cũng đã đóng phần quan trọng Sau khi thử các tham số và một loạt thao tác, tôi tin rằng bạn đã hiểu rõ về sự phát triển cơ bản.
Cuối cùng, có hai câu hỏi còn lại tôi tin rằng bạn cũng sẽ có sự nhầm lẫn tương tự.
Bạn có thể cho biết sự khác biệt giữa luồng ảo và luồng phụ thông thường không? Bài viết trước đã kiểm chứng rằng hiệu năng không có nhiều khác biệt. Có cách nào khác để quan sát và phân biệt không?
Bạn có thể đi sâu hơn một chút và chỉ sử dụng một @RunOnVirtualThread Tôi buộc mình phải viết hai bài blog chỉ bằng cách bình luận về chúng. Điều đó thực sự quá lừa dối.
Các vấn đề trên sẽ được giải quyết trong phần tiếp theo "Web Framework hỗ trợ phân luồng ảo JDK19, Chương cuối cùng". Đây vẫn là khẩu hiệu quảng cáo quen thuộc: Xinchen nguyên bản, nó sẽ đáp ứng được mong đợi của bạn.
Chào mừng đến với vườn blog: Lập trình viên Xin Chen
Trên con đường học tập, bạn không đơn độc, Xinchen Original luôn đồng hành cùng bạn...
Cuối cùng, bài viết này về khung web hỗ trợ các luồng ảo JDK19, Phần 2: Sự phát triển hoàn chỉnh của ứng dụng quarkus hỗ trợ các luồng ảo, sẽ kết thúc tại đây. Nếu bạn muốn biết thêm về khung web hỗ trợ các luồng ảo JDK19, Phần 2. : Để phát triển hoàn chỉnh ứng dụng quarkus hỗ trợ các luồng ảo, vui lòng tìm kiếm các bài viết CFSDN hoặc tiếp tục duyệt các bài viết liên quan. Tôi hy vọng bạn sẽ ủng hộ blog của tôi trong tương lai! .
Câu hỏi này đã có câu trả lời: R: Chuyển đổi chuỗi phân cách thành biến (3 câu trả lời) Đã đóng 5 năm trước. Tôi có một bảng chứa dữ liệu phim và ở cột cuối cùng chứa phim mà nó thuộc về
Đầu tiên, tôi đến từ cộng đồng Java và vẫn đang là người học C++. Hãy xem các lớp bên dưới. Hình ảnh thứ hai hiển thị các lớp con của lớp "GameObject". Nó cũng có phương thức Display(). Lớp GameObject có 5 lớp con,
Tôi đang gặp một số vấn đề ở đây. Tôi đang cố gắng làm cho mã của mình hoạt động giống như một giao diện trong java. Lớp này được kế thừa bởi 2 lớp khác vì chúng gây ra một số vấn đề. Và tôi cũng muốn biết liệu tôi có làm đúng hay không và cách cải thiện mã của mình. tôi là người mới
Trong C++, tôi có lớp cơ sở A và lớp con B. Cả hai đều có phương thức ảo Visit. Tôi muốn xác định lại "quyền truy cập" trong B, nhưng B cần truy cập mọi chức năng "truy cập" của A (và tất cả các lớp con). Tôi có cái gì đó tương tự nhưng nó cho tôi biết B Không có
Tôi có một lớp trừu tượng là gốc của hệ thống phân cấp lớp. Lớp gốc có một phương thức với một số cách triển khai đơn giản và dường như không cần phải thay đổi cách triển khai đó ở mọi nơi. Làm cho phương thức này không ảo cũng được, nhưng một số lớp con có thể vô tình triển khai lại nó. Trong trường hợp này, bên ảo cuối cùng
Trên MSDN, tôi thấy rằng việc sử dụng công cụ sửa đổi "ảo" trên khai báo phương thức trừu tượng là một lỗi. Một trong những đồng nghiệp của tôi được cho là một nhà phát triển rất có kinh nghiệm, nhưng anh ấy đã sử dụng điều này trong mã của mình: public abstract class Busi
Bảng hàm ảo C++ chỉ được sử dụng để xác định đoạn mã nào sẽ được thực thi khi hàm ảo được gọi hay nó có các mục đích sử dụng khác trong thời gian chạy? Trên Wikipedia nó liệt kê "công văn động" là một lý do, nhưng không đi sâu vào chi tiết hơn về C++... Câu trả lời hay nhất Một số cách triển khai
Kích thước trang có cố định không? Cụ thể hơn, getconf PAGE_SIZE cho 4096, đủ công bằng. Nhưng điều này có thể thay đổi được theo thời gian chạy của chương trình không? Hay nó không đổi trong suốt quá trình hệ điều hành xuất hiện. tức là. , liệu quá trình này có thể thực hiện được
Sự khác biệt giữa các hàm hủy (và tất nhiên là các hàm tạo) và các hàm thành viên khác là nếu một hàm thành viên thông thường có phần thân trong lớp dẫn xuất thì chỉ phiên bản trong lớp dẫn xuất được thực thi. Và trong trường hợp hàm hủy, cả phiên bản dẫn xuất và phiên bản lớp cơ sở sẽ được thực thi? Thật tốt khi biết rằng trong hàm hủy (có thể
Chính xác thì điều đó có nghĩa là gì nếu một hàm được định nghĩa là ảo và giống với một hàm ảo thuần túy? Câu trả lời hay nhất đến từ hàm Virtual của Wikipedia... Trong chương trình hướng đối tượng
Tôi có một ứng dụng chạy dưới Jetty mà tôi muốn trả về URL tuyệt đối tự tham chiếu (khi tạo nguồn cấp dữ liệu RSS, vì vậy ứng dụng khách phải có thể hoạt động mà không cần ngữ cảnh "URL hiện tại"). Vấn đề là tôi không biết trước ứng dụng sẽ được triển khai
Làm cách nào để sao chép giữa hai virtualtreeviews để sao chép tất cả các cột, không chỉ cột đầu tiên? Trước khi sao chép: Sau khi sao chép: Điều khiển Best Answer Tree không lưu bất kỳ dữ liệu nào. Nó không chứa dữ liệu cột cần hiển thị nên không thể sao chép được. Thay vào đó, khi điều khiển cây muốn hiển thị bất kỳ
Tôi đã đặt ShowHint thành true và HintMode thành hmToolTip, nhưng khi tôi di con trỏ qua điều khiển, trình xử lý sự kiện OnGetHint() của tôi thậm chí không có điểm dừng. biết tôi đã làm gì sai
Bạn tôi đang làm việc với VirtualTreeView ở Delphi và gặp phải vấn đề tiếp theo: anh ấy có hai cột, cột đầu tiên có dữ liệu và các phần tử con trong mỗi hàng. Có thể đặt chiều rộng cột con tối đa mà không thay đổi độ rộng cột đầu tiên không? huyền thoại:
Tôi đang sử dụng TVirtualStringTree trong Thành phần Virtual TreeView của mình (một phần của dự án Delphi) Tôi muốn tạo Chế độ xem trong đó 2 cột có thể có
Tôi muốn lặp qua tất cả các gốc của VirtualTreeView và xóa chúng. Tôi không muốn xóa nó. Tôi đang gặp phải vi phạm quyền truy cập với mã này: var Node : PVirtualNode started if VirtualStri;
Tôi có một tệp PHP xuất ra một biểu mẫu. Tôi muốn gọi tệp PHP này ở phía máy chủ (hiện đang sử dụng "bao gồm"), hãy điền và gửi nó. Điều này tốt hơn nên tôi không phải can thiệp vào biểu mẫu PHP thực tế và chỉ cần xử lý lớp trình bày để dữ liệu có thể được
Tôi là một lập trình viên xuất sắc, rất giỏi!